Вопрос по django, django-models –  модель например):

311

разница между django OneToOneField и ForeignKey?

Ваш Ответ

6   ответов
413

OneToOneField(SomeModel) а такжеForeignKey(SomeModel, unique=True), Как указано вПолное руководство по Джанго:

OneToOneField

Отношения один-к-одному. Концептуально это похоже наForeignKey с участиемunique=True, но «обратная» сторона отношения будет напрямую возвращать один объект.

В отличие отOneToOneField «обратное» отношение, аForeignKey «обратное» отношение возвращаетQuerySet.

пример

Например, если у нас есть следующие две модели (полный код модели ниже):

Car модель используетOneToOneField(Engine)Car2 модель используетForeignKey(Engine2, unique=True)

Изнутриpython manage.py shell выполнить следующее:

OneToOneField пример
>>> from testapp.models import Car, Engine
>>> c = Car.objects.get(name='Audi')
>>> e = Engine.objects.get(name='Diesel')
>>> e.car
<Car: Audi>
ForeignKey с участиемunique=True пример
>>> from testapp.models import Car2, Engine2
>>> c2 = Car2.objects.get(name='Mazda')
>>> e2 = Engine2.objects.get(name='Wankel')
>>> e2.car2_set.all()
[<Car2: Mazda>]
Код модели
from django.db import models

class Engine(models.Model):
    name = models.CharField(max_length=25)

    def __unicode__(self):
        return self.name

class Car(models.Model):
    name = models.CharField(max_length=25)
    engine = models.OneToOneField(Engine)

    def __unicode__(self):
        return self.name

class Engine2(models.Model):
    name = models.CharField(max_length=25)

    def __unicode__(self):
        return self.name

class Car2(models.Model):
    name = models.CharField(max_length=25)
    engine = models.ForeignKey(Engine2, unique=True, on_delete=models.CASCADE)

    def __unicode__(self):
        return self.name
@MarkPNeyer: насколько я понимаю, поле OneToOne - это всего лишь одно к одному. Это не должно быть на. Видетьэтот пример: место не обязательно должно быть рестораном osa
Этот ответ говорит: «Есть некоторые различия», а затем называет одно отличие. Есть ли другие? Chris Martin
Есть ли фундаментальная причина, по которой у Django не могло быть такого правила, что если внешний ключ уникален и не равен нулю, тоe.car тоже работает? Ciro Santilli 新疆改造中心 六四事件 法轮功
Итак ... когда бы кто-нибудь захотел использоватьForeignKey с участиемunique=True а неOneToOneField? Я вижу в других вопросах, что Джанго даже предупреждает, чтоOneToOneField обычно лучше всего служат интересам. ОбратноеQuerySet никогда не будет иметь более одного элемента, верно? Andy
Мне интересно так же, как Крис. Является ли это просто синтаксическим сахаром, есть ли какое-то основное различие в доступе к данным, приводящее к различиям в производительности? Carlos
26

изучить примеры из реальной жизни. Предположим на мгновение, что вы хотите создать блог в Django, где журналисты могут писать и публиковать новостные статьи. Владелец интернет-газеты хочет разрешить каждому из своих репортеров публиковать столько статей, сколько они хотят, но не хочет, чтобы разные репортеры работали над одной и той же статьей. Это означает, что когда читатели пойдут и прочитают статью, они увидят в ней только одного автора.

Например: статья Джона, статья Гарри, статья Рика. Вы не можете иметь статью Гарри и Рика, потому что босс не хочет, чтобы два или более авторов работали над одной и той же статьей.

Как мы можем решить эту «проблему» с помощью Django? Ключом к решению этой проблемы является ДжангоForeignKey.

Ниже приведен полный код, который можно использовать для реализации идеи нашего босса.

from django.db import models

# Create your models here.

class Reporter(models.Model):
    first_name = models.CharField(max_length=30)

    def __unicode__(self):
        return self.first_name


class Article(models.Model):
    title = models.CharField(max_length=100)
    reporter = models.ForeignKey(Reporter)

    def __unicode__(self):
        return self.title

Бегатьpython manage.py syncdb выполнить SQL-код и построить таблицы для вашего приложения в вашей базе данных. Тогда используйтеpython manage.py shell открыть оболочку Python.

Создайте объект Reporter R1.

In [49]: from thepub.models import Reporter, Article

In [50]: R1 = Reporter(first_name='Rick')

In [51]: R1.save()

Создайте объект Article A1.

In [5]: A1 = Article.objects.create(title='TDD In Django', reporter=R1)

In [6]: A1.save()

Затем используйте следующий фрагмент кода, чтобы получить имя репортера.

In [8]: A1.reporter.first_name
Out[8]: 'Rick'

Теперь создайте объект Reporter R2, выполнив следующий код Python.

In [9]: R2 = Reporter.objects.create(first_name='Harry')

In [10]: R2.save()

Теперь попробуйте добавить R2 к объекту Article A1.

In [13]: A1.reporter.add(R2)

Это не работает, и вы получите AttributeError о том, что объект 'Reporter' не имеет атрибута 'add'.

Как видите, объект Article не может быть связан с несколькими объектами Reporter.

Что насчет R1? Можем ли мы прикрепить к нему более одного объекта Article?

In [14]: A2 = Article.objects.create(title='Python News', reporter=R1)

In [15]: R1.article_set.all()
Out[15]: [<Article: Python News>, <Article: TDD In Django>]

Этот практический пример показывает нам, что ДжангоForeignKey используется для определения отношений многие-к-одному.

OneToOneField используется для создания отношений один-к-одному.

Мы можем использоватьreporter = models.OneToOneField(Reporter) в приведенном выше файле models.py, но он не будет полезен в нашем примере, так как автор не сможет опубликовать более одной статьи.

Каждый раз, когда вы хотите опубликовать новую статью, вам нужно будет создать новый объект Reporter. Это отнимает много времени, не так ли?

Я настоятельно рекомендую попробовать пример сOneToOneField и понять разницу. Я уверен, что после этого примера вы будете полностью знать разницу между DjangoOneToOneField и джангоForeignKey.

1

вы получаете значение поля, которое вы запросили. В этом примере поле 'title' модели книги - это OneToOneField:

>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'

Когда вы получаете доступ к ForeignKey, вы получаете связанный объект модели, к которому вы можете затем выполнить дальнейшие запросы. В этом примере поле 'publisher' той же модели книги - это ForeignKey (соответствует определению модели класса Publisher):

>>> b = Book.objects.get(id=50)
>>> b.publisher
<Publisher: Apress Publishing>
>>> b.publisher.website
u'http://www.apress.com/'

С полями ForeignKey запросы работают и в другом направлении, но они немного отличаются из-за несимметричного характера отношений.

>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]

За кулисами book_set является просто QuerySet и может быть отфильтрован и нарезан как любой другой QuerySet. Имя атрибута book_set генерируется путем добавления названия модели в нижнем регистре к _set.

89

поэтому у объекта Car может быть много Колес, каждое из которых имеет ForeignKey для Автомобиля, которому он принадлежит. OneToOneField был бы похож на Engine, где объект Car может иметь один и только один объект.

Да: «OneToOneField по сути такой же, как ForeignKey, за исключением того, что оно всегда содержит« уникальное »ограничение, а обратное отношение всегда возвращает объект, на который указывает (поскольку он будет только один), а не возвращает список.' Dan Breen
спасибо, Dose OneToOneField (someModel) означает ForeignKey (SomeModel, unique = True)? redice
Как насчет нескольких автомобилей, имеющих один и тот же двигатель? Oleg Belousov
@OlegTikhonov У них может бытькопия с тем же дизайном двигателя, но я хотел бы видеть случай, когда несколько автомобилей используют один и тот же физический двигатель. Dan Breen
В этом ответе есть небольшая путаница с терминами. ForeignKey - это не один-ко-многим, но это отношение многих-к-одному, согласно официальной документации django:docs.djangoproject.com/en/2.0/ref/models/fields/... Kutay Demireren
1

ТакжеOneToOneField полезно использовать в качестве первичного ключа, чтобы избежать дублирования ключа. Можно не иметь неявного / явного автополя

models.AutoField(primary_key=True)

но использоватьOneToOneField в качестве первичного ключа вместо (представьтеUserProfile модель например):

user = models.OneToOneField(
    User, null=False, primary_key=True, verbose_name='Member profile')
10

композиции, в то время как ForeignKey (один-ко-многим) относится к агрегации.

Похожие вопросы