Использование OneToOneField в Django
Я очень запутался в использовании OnetoOneField
. Я думал, что он предназначен для случая, когда данная запись может иметь только 1 ссылку на другую таблицу. Например, у дочерней записи есть 1 родительская.
Но похоже, что Django делает поле, определенное как OneToOne, первичным ключом вашей таблицы, что означает, что оно имеет ограничение Unique. Это не имеет никакого смысла. У любого ребенка есть только 1 родитель. Но может быть более одного ребенка с одним и тем же родителем. FK родителя не будет уникальным во всей таблице Child
Я хотел использовать OneToOne вместо ForeignKey, чтобы обеспечить аспект "один к одному", в отличие от ForeignKey, который является 1 ко многим (любой данный ребенок может иметь более одного родителя).
Я не прав в своем понимании? Должен ли я вернуться к использованию ForeignKey и просто убедиться, что мой код обеспечивает 1-1?
Я нашел эти другие ссылки, в которых задается тот же вопрос, но не уверен, что увидел окончательный ответ Зачем кому-то устанавливать primary_key=True для отношения "один к одному" (OneToOneField)? OneToOneField() vs ForeignKey() в Django
A OneToOneField
может немного ввести в заблуждение, на самом деле это поле ноль/один-к-одному. Обычно оно используется для связи экземпляров модели A с экземплярами модели B, но при этом два экземпляра A не могут ссылаться на один и тот же экземпляр B. Типичный случай использования - это, например, если у вас есть модель Employee
s, и для некоторых Employee
s вам нужно хранить дополнительные данные. Но это часто является некоторым антипаттерном: если у вас есть контроль над моделью B (потому что она не реализована в другом пакете), вы не можете добавить (nullable) поля в B, и тогда вы можете сделать модель A с дополнительными данными и указать OneToOneField
из A в B. Это также можно использовать, если количество полей будет большим, а количество записей B, имеющих связанную запись A, небольшим. В этом случае создание дополнительных nullable-полей может сильно раздуть базу данных. В пакетах Django по умолчанию (django.contrib
) она вообще не используется.
A OneToOneField
however has a use-case for which Django uses a OneToOneField
in a hidden matter: model inheritance [Django-doc]. Indeed, if you make two models:
class Foo(models.Model):
pass
class Bar(Foo):
pass
Тогда это две конкретные модели. Django реализует это, создав две таблицы, одну для foo
и одну для bar
. Первичным ключом Bar
будет OneToOneField
, который ссылается на таблицу Foo
. Таким образом, они разделяют одно и то же "пространство идентификаторов", и это также гарантирует, что для одного Foo
не будет создано двух Bar
. Однако это не препятствует созданию записи Qux
с тем же id, если Qux
также является подклассом Foo
, так что это не "идеальный" способ представления наследования. Кроме того, наследование в реляционных базах данных часто также не является хорошей идеей, поскольку требует дополнительных JOIN.
Подведем итоги: OneToOneField
часто используются для добавления данных в уже существующую модель, которую мы не очень контролируем, или когда количество записей с дополнительными данными невелико и может привести к взрыву хранилища. Но использовать их следует с умом.
Анекдот: Я пользовался этим, потому что Django не очень ясно показывает, какая сессия принадлежит какому пользователю. Это кодируется в данных сессии, но нелегко отфильтровать, например, какие сессии принадлежат определенному пользователю. Затем я использовал OneToOneField
для ссылки на Session
, чтобы не создавать много лишних записей.