Django:为什么要创建一个 OneToOne 到 UserProfile,而不是子类化 auth.User?

发布于 2024-10-26 12:15:25 字数 355 浏览 6 评论 0原文

注意:如果您想通过告诉我您不喜欢 django.contrib.auth 来“回答”这个问题,请继续。那不会有帮助。我很清楚关于这个问题的意见的范围和强度。

现在的问题是:

惯例是创建一个模型 UserProfile,其中包含 OneToOne 到 User。

在我能想到的各种方式中,一种更高效和有效的方法是将 User 子类化为一个打算用于系统中每个人的类 - 一个名为 Person(User) 的类。

我还没有看到一个连贯的解释为什么前者是常规的而后者被视为黑客。不久前,我改用了 OneToOne 方法以获得使用 get_profile() 的能力,但从那以后我就后悔了。我正在考虑切换回来,除非我能够理解这种方法的优点。

Note: If you are tempted to 'answer' this question by telling me that you don't like django.contrib.auth, please move on. That will not be helpful. I am well aware of the range and strength of opinions on this matter.

Now, the question:

The convention is to create a model, UserProfile, with a OneToOne to User.

In every way I can think of, a more efficient and effective approach is to subclass User to a class that one intends to use for every human in the system - a class called, say, Person(User).

I have not seen a coherent explanation of why the former is conventional and the latter is regarded as a hack. A while ago, I changed over to the OneToOne approach so as to gain the ability to use get_profile() and I have regretted it ever since. I'm thinking of switching back unless I can be made to understand the advantage of this approach.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

离线来电— 2024-11-02 12:15:25

您确实意识到,模型子类化是通过底层的 OneToOne 关系实现的,不是吗?事实上,就效率而言,我看不出这两种方法有什么区别。

在我看来,现有具体模型的子类化是一种令人讨厌的黑客行为,应该尽可能避免。它涉及隐藏数据库关系,以便不清楚何时执行额外的数据库访问。显式显示关系并在必要时显式访问它们会更加清晰。

现在,我喜欢的第三种选择是创建一个全新的用户模型,以及一个返回新模型实例而不是默认模型实例的自定义身份验证后端。创建后端只需要定义几个简单的方法,因此非常容易做到。

You do realise, don't you, that model subclassing is implemented by means of a OneToOne relationship under the hood? In fact, as far as efficiency is concerned, I cannot see any difference at all between these two methods.

Subclassing of existing concrete models is, in my opinion, a nasty hack that should be avoided if at all possible. It involves hiding a database relationship so that it is unclear when extra db access is performed. It's much clearer to show the relationships explicitly, and access them explicitly where necessary.

Now, a third alternative which I do like is to create a completely new User model, along with a custom authentication backend that returns instances of the new model instead of the default one. Creating a backend only involves defining a couple of simple methods, so it's very easy to do.

贱贱哒 2024-11-02 12:15:25

从来没有一个真正好的解释,至少从“官方”来源来看,为什么在实践中,子类化 User 不如拥有 UserProfile 有用。

然而,我有几个原因,是在我自己决定对 User 进行子类化是“可行的方法”之后出现的。

  • 您需要一个自定义身份验证后端。这不是一个大问题,但是您需要编写的代码越少越好。
  • 其他应用程序可能会假设您的用户是 django.contrib.auth.models.User。大多数情况下这是可以的,除非该代码正在获取 User 对象。因为我们是一个子类,所以任何仅使用 User 对象的代码都应该没问题。
  • 一个用户一次只能“成为”一个子类。例如,如果您有学生和教师的用户子类,那么在给定时间,您的用户只能是教师或学生。使用用户配置文件,同一用户可以同时附加教师和学生配置文件。
  • 接下来,从一个子类转换为另一个子类是很困难的:特别是如果您已经有一个子类的实例。

因此,您可能会说,“我的项目将只有一个 User 子类”。我就是这么想的。现在我们有三个,加上普通用户,可能还有第四个。 需求发生变化,必须更改大量代码来处理这种情况并不是很有趣。

注意:最近 django-developers 上有很多关于更好地修复与 contrib.auth User 模型相关的问题的讨论。

There's never really been a good explanation, at least from "official" sources as to why, in practice, subclassing User is less useful than having a UserProfile.

However, I have a couple of reasons, that came up after I had decided myself that subclassing User was "the way to go".

  • You need a custom authentication backend. This is not a big issue, but the less code you need to write, the better.
  • Other apps may be assuming that your User is a django.contrib.auth.models.User. Mostly this will be okay, unless that code is fetching User objects. Because we are a subclass, any code just using our User objects should be fine.
  • A User may only 'be' one sub-class at a time. For instance, if you had User subclasses of Student and Teacher, then at a given time, your User would only be able to be a Teacher or a Student. With UserProfiles, there could be both a Teacher and a Student profile attached to the same user at the same time.
  • Following on, converting from one sub-class to another is hard: especially if you have an instance of one sub-class already.

So, you may say, "my project will only ever have the one User subclass". That's what I thought. Now we have three, plus regular Users, and possibly a fourth. Requirements change, having to change heaps of code to deal with that is not much fun.

note: There has been quite a lot of discussion on django-developers recently about a better fix to the issues related to the contrib.auth User model.

帥小哥 2024-11-02 12:15:25

继承User模型是不是更加高效有效呢?我不明白为什么,但我想读一下你的论点。 IMNSHO,模型继承一直是一个痛苦。

然而,这可能无法回答您的问题,但我对 Will Hardy 在此片段<中提出的解决方案非常满意/a>.通过利用信号,它会自动为每个新用户创建一个新的用户配置文件。

该链接不太可能消失,但这是我的代码的略有不同的版本:

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')

当然,任何功劳都归于威尔·哈迪(Will Hardy)。

Is it more efficient and effective to inherit the User model? I don't see why, but I'd like to read your arguments. IMNSHO, model inheritance has always been a pain.

Yet, this may not answer your question, but I'm quite satisfied with the solution proposed by Will Hardy in this snippet. By taking advantage of signals, it automatically creates a new user profile for every new user.

The link is unlikely to disappear, but here's my slightly different version of his code:

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')

Of course, any credit goes to Will Hardy.

无力看清 2024-11-02 12:15:25
  1. 如果您只有一种类型的用户,例如任何社交媒体网站 Facebook 或 Instagram,那么请选择继承。

  2. 如果您的应用程序有不同类型的用户,例如帐户、学生、教师、库存经理,则选择 oneToone 关系。

  1. If you are having just one type of user, like any social media site facebook or Instagram then go for inheritance.

  2. If your application has different type of users, like accounts, student, teacher, inventory manager then go for oneToone relationship.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文