Django: при расширении User лучше использовать OneToOneField (User) или ForeignKey (User, unique = True)? - PullRequest
29 голосов
/ 11 июля 2010

Я нахожу противоречивую информацию о том, использовать ли 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 Book используется ForeignKey.

Джеймс Беннетт также имеет два сообщения в блоге, которые также содержат противоречивые примеры:

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

Мне интересно узнать ваши предпочтения и почему.Или это вообще имеет значение?

Ответы [ 3 ]

18 голосов
/ 11 июля 2010

Единственная реальная причина, приведенная в статье, заключается в том, что ее можно настроить так, чтобы на странице администратора для User отображались оба поля в User и UserProfile.Это может быть воспроизведено с помощью OneToOneField с небольшой консистентной смазкой, так что, если вы не привыкли показывать его на странице администратора без каких-либо усилий за счет некоторой ясности («Мы можем создать несколько профилей на пользователя ?!О нет, подожди, он уникален. ") Я бы использовал OneToOneField.

7 голосов
/ 09 августа 2010

Помимо встроенной страницы администратора, другая причина решения 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, но даже это может дать сбой из-за некоторых неизвестных меня раздражают автоматические менеджеры. Насколько я помню, в приведенном выше примере это не получится.

5 голосов
/ 17 ноября 2010

Другая причина обычно не использовать OneToOneField, относящуюся к обратным отношениям: когда вы используете обратные отношения, определенные с помощью OneToOneField, вы получаете экземпляр модели, в отличие от Manager для ForeignKey обратного отношения, и, как следствие, всегда ударил БД. Это дорого обходится, если вы делаете некоторые общие вещи для обратных отношений (через _meta.get_all_related_objects()) и не знаете и не заботитесь, будете ли вы использовать их все или нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...