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()) и не знаю, и все равно, будете ли вы использовать их все или нет.

Другие вопросы по тегам