Django OneToOneField - в какую модель его поставить? - PullRequest
10 голосов
/ 21 марта 2012

Предположим, у нас есть следующие модели.

class A(Model): pass
class B(Model): pass

Тогда нет никакой разницы между:

В модели A: b = OneToOneField(B, related_name=A.__name__)

и

в модели B: a = OneToOneField(A, related_name=B.__name__)

Итак, какие вопросы я должен задать себе, чтобы решить, следует ли помещать OTO в ту или иную модель. Я имею в виду, как есть, есть и так далее.

Ответы [ 4 ]

25 голосов
/ 24 мая 2012

На самом деле есть разница в том, куда вы помещаете однозначное поле, потому что удаление ведет себя по-разному. Когда вы удаляете объект, любые другие объекты, имеющие отношения один к одному, ссылающиеся на этот объект, будут удалены. Если вместо этого вы удаляете объект, содержащий однозначное поле (то есть оно ссылается на другие объекты, но другие объекты не ссылаются на него), другие объекты не удаляются.

Например:

class A(models.Model):
    pass

class B(models.Model):
    a = models.OneToOneField(A)

Если вы удалите A, по умолчанию B также будет удален (хотя вы можете переопределить это, изменив аргумент on_delete для OneToOneField, как и ForeignKey ). Удаление B не приведет к удалению A (хотя вы можете изменить это поведение, переопределив метод delete () в B).

Возвращаясь к вашему первоначальному вопросу «имеет-а против-есть-а», если у A есть B, у B должно быть поле «один к одному» (B должно существовать, только если существует A, но A может существовать без B ).

8 голосов
/ 21 марта 2012

OneToOneField на самом деле предназначены только для двух целей: 1) наследование (Django использует их для реализации MTI) или 2) расширение не редактируемой модели (например, создание UserProfile для User).

В этих двух сценариях очевидно, какая модель OneToOneField используется. В случае наследства это переходит на ребенка. В случае расширения это относится к единственной модели, к которой вы имеете доступ.

С очень несколькими исключениями любое другое использование "один к одному" действительно должно быть просто объединено в одну модель.

1 голос
/ 21 марта 2012

Я думаю, что в случае с полем OneToOne правильный ответ заключается в том, что это не имеет значения, это просто зависит от того, какую модель имеет смысл связать с другой.

0 голосов
/ 13 августа 2013

Кстати, мне нужно было OneToOneField для предотвращения циклической зависимости (использование наследования):

Model A:
  ...
  current_choice = models.ForeignKey(B)

Model B:
  ...
  parent = models.ForeignKey(A)

Это означает, что A нужно определить B.Не очень хорошее соглашение с базой данных для начальной загрузки.Вместо этого я сделал:

Model A:
  ...

Model B:
  ...
  parent = models.ForeignKey(A)

Model C:
  parent = models.OneToOneField(A)
  current_choice = models.ForeignKey(B)

Что касается примера из документации , у вас также могут быть чистые запросы, например: p1.restaurant.place.restaurant.place ... Это безумие.

...