Django: при расширении User лучше использовать OneToOneField(User) или ForeignKey(User, unique=True)?
Я нахожу противоречивую информацию о том, использовать ли OneToOneField(User)
или же ForeignKey(User, unique=True)
при создании UserProfile
модели путем расширения модели пользователя Django.
Это лучше использовать?
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
или это?:
class UserProfile(models.Model):
user = models.OneToOneField(User)
Django Doc определяет OneToOneField
в то время как пример книги Django использует ForeignKey
,
У Джеймса Беннетта также есть два сообщения в блоге, которые также содержат противоречивые примеры:
В предыдущем посте Беннетт приводит некоторые причины, по которым он перешел на использование ForeignKey
вместо OneToOneField
, но я не совсем понимаю, особенно когда вижу другие посты, которые рекомендуют обратное.
Мне интересно узнать ваши предпочтения и почему. Или это вообще имеет значение?
3 ответа
Единственная реальная причина, приведенная в статье, заключается в том, что ее можно настроить так, чтобы страница администратора User
покажет оба поля в User
а также UserProfile
, Это может быть воспроизведено с OneToOneField
с небольшим количеством консистентной смазки, так что, если вы не привыкли показывать его на странице администратора без каких-либо усилий, затрачивая немного ясности ("Мы можем создать несколько профилей для каждого пользователя?! О нет, подождите, он установлен уникальным. Я бы использовал OneToOneField
,
Помимо встроенной страницы администратора, есть и другая причина ForeignKey
Решение заключается в том, что он позволяет вам использовать правильный менеджер БД по умолчанию, когда к объектам обращаются по обратной связи. Рассмотрим пример из этого фрагмента менеджера подклассов. Допустим, что Post
Определение класса из примера выглядит так:
class Post(ParentModel):
title = models.CharField(max_length=50)
onetoone = models.ForeignKey(SomeModel, unique=True)
children = ChildManager()
objects = models.Manager()
По телефону somemodel_instance.post_set.all()[0]
, вы получите нужные подклассы объектов Post
класс, как указано путем определения первого (по умолчанию) менеджера как ChildManager
, С другой стороны, с OneToOneField
по телефону somemodel_instance.post
вы получаете Post
экземпляр класса. Вы всегда можете позвонить somemodel_instance.post.subclass_object
и получить тот же результат, но менеджер по умолчанию может сделать любой другой вид трюков и FK
решения хорошо их скрывают.
Если вы владеете и можете изменить пользовательский код менеджера, вы можете использовать use_for_related_fields
атрибут вместо использования FK вместо законного поля 1to1, но даже это может дать сбой из-за некоторых неизвестных мне неприятностей автоматических менеджеров. Насколько я помню, это не удастся в приведенном выше примере.
Другая причина, как правило, не использовать OneToOneField
связанные с обратными отношениями: когда вы используете обратные отношения, определенные с помощью OneToOneField
Вы получаете образец модели, вопреки Manager
за ForeignKey
обратная связь и, как следствие, всегда есть попадание в БД. Это дорого, если вы делаете какие-то общие вещи по обратным отношениям (через _meta.get_all_related_objects()
) и не знаю, и все равно, будете ли вы использовать их все или нет.