Подтвердить что ты не робот

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, но я не совсем понял его, особенно когда вижу другие сообщения, которые рекомендуют обратное.

Мне любопытно узнать ваше предпочтение и почему. Или это даже имеет значение?

4b9b3361

Ответ 1

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

Ответ 2

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

Ответ 3

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