Джанго: Зачем создавать OneToOne для UserProfile вместо создания подкласса auth.User? - PullRequest
9 голосов
/ 28 марта 2011

Примечание. Если вы захотите «ответить» на этот вопрос, сказав, что вам не нравится django.contrib.auth, пожалуйста, продолжайте.Это не поможет.Я хорошо осведомлен о разнообразии и силе мнений по этому вопросу.

Теперь вопрос:

Соглашение заключается в создании модели UserProfile с OneToOne to User.

Во всех отношениях, которые я могу придумать, более эффективным и действенным подходом является создание подкласса User для класса, который предполагается использовать для каждого человека в системе, - класса, который называется, скажем, Person (User).*

Я не видел связного объяснения того, почему первое является общепринятым, а второе считается хаком.Некоторое время назад я перешел на подход OneToOne, чтобы получить возможность использовать get_profile (), и с тех пор я сожалел об этом.Я думаю о том, чтобы вернуться назад, если меня не заставят понять преимущество этого подхода.

Ответы [ 3 ]

4 голосов
/ 28 марта 2011

Вы понимаете, не правда ли, что подклассы моделей реализуются посредством взаимосвязи OneToOne под капотом?На самом деле, что касается эффективности, я не вижу никакой разницы между этими двумя методами.

Подклассификация существующих конкретных моделей - это, на мой взгляд, неприятный взлом, которого следует избегать, если это вообще возможно,Он включает в себя сокрытие отношений с базой данных, поэтому неясно, когда выполняется дополнительный доступ к БД.Гораздо понятнее явным образом показать отношения и обращаться к ним явно, где это необходимо.

Теперь третий вариант, который мне нравится, - это создание совершенно новой модели User вместе с пользовательским бэкэндом аутентификации, который возвращает экземплярыновая модель вместо модели по умолчанию.Создание бэкэнда требует только определения нескольких простых методов, поэтому это очень легко сделать.

2 голосов
/ 10 июля 2012

Никогда не было хорошего объяснения, по крайней мере из «официальных» источников, почему на практике создание подкласса User менее полезно, чем наличие UserProfile.

Однако у меня есть несколько причин,это возникло после того, как я сам решил, что создание подкласса User - это «путь».

  • Вам необходим пользовательский сервер аутентификации.Это не большая проблема, но чем меньше кода вам нужно написать, тем лучше.
  • Другие приложения могут предполагать, что ваш пользователь - django.contrib.auth.models.User.В основном это будет хорошо, если только этот код не выбирает объекты пользователя.Поскольку мы подкласс, любой код, использующий только наши объекты User, должен быть в порядке.
  • Пользователь может «быть» только одним подклассом за раз.Например, если у вас есть пользовательские подклассы ученика и учителя, то в определенный момент времени ваш пользователь сможет быть только учителем или учеником.При использовании UserProfiles к одному и тому же пользователю могут быть одновременно подключены профили учителей и учеников.
  • После этого переход из одного подкласса в другой затруднен: особенно если у вас есть экземпляруже один подкласс.

Итак, вы можете сказать, что «мой проект будет иметь только один подкласс пользователя».Это то, о чем я думал.Теперь у нас есть три плюс постоянные пользователи и, возможно, четвертый. Изменение требований , менять кучу кода, чтобы справиться с этим, не очень весело.

note: Было много дискуссий о django-developersнедавно о лучшем решении проблем, связанных с моделью пользователей contrib.auth.

0 голосов
/ 28 марта 2011

Является ли более эффективным и действенным наследовать модель User? Я не понимаю почему, но я хотел бы прочитать ваши аргументы. ИМНШО, наследование модели всегда было болью.

Тем не менее, это может не ответить на ваш вопрос, но я вполне удовлетворен решением, предложенным Уиллом Харди в этом фрагменте . Используя преимущества сигналов, он автоматически создает новый профиль пользователя для каждого нового пользователя.

Ссылка вряд ли исчезнет, ​​но вот моя немного другая версия его кода:

from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _

class AuthUserProfileModelBase(models.base.ModelBase):
    # _prepare is not part of the public API and may change
    def _prepare(self):
        super(AuthUserProfileModelBase, self)._prepare()
        def on_save(sender, instance, created, **kwargs):
            if created:
                self.objects.create(user=instance)
        # Automatically link profile when a new user is created
        post_save.connect(on_save, sender=User, weak=False)

# Every profile model must inherit this class
class AuthUserProfileModel(models.Model):
    class Meta:
        abstract = True
    __metaclass__ = AuthUserProfileModelBase
    user = models.OneToOneField(User, db_column='auth_user_id',
        primary_key=True, parent_link=True)

# The actual profile model
class Profile(AuthUserProfileModel):
    class Meta:
        app_label = 'some_app_label'
        db_table = 'auth_user_profile'
        managed = True
    language = models.CharField(_('language'), max_length=5, default='en')

Конечно, любая заслуга принадлежит Уиллу Харди.

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