Django - 多个用户配置文件

Posted

技术标签:

【中文标题】Django - 多个用户配置文件【英文标题】:Django - Multiple User Profiles 【发布时间】:2012-03-27 20:28:06 【问题描述】:

最初,我的 UserProfile 是这样开始的:

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    verified = models.BooleanField()
    mobile = models.CharField(max_length=32)

    def __unicode__(self):
        return self.user.email

settings.py 中设置的AUTH_PROFILE_MODULE = 'accounts.UserProfile' 配合得很好。

但是,我的网站中有两种不同类型的用户,个人和公司,每个用户都有自己独特的属性。例如,我希望我的个人用户只有一个用户,因此拥有user = models.OneToOneField(User),而对于企业,我希望他们拥有多个与同一个人资料相关的用户,所以我将拥有user = models.ForeignKey(User)

所以我考虑将模型分成两个不同的模型,IndivProfileCorpProfile,它们都继承自 UserProfile,同时将特定于模型的属性移动到相关的子模型中。对我来说似乎是个好主意,并且可能会起作用,但是我无法以这种方式指定 AUTH_PROFILE_MODULE,因为我有两个不同用户的用户配置文件。

我也想过反过来做,让UserProfile从多个类(模型)继承,像这样:

class UserProfile(IndivProfile, CorpProfile):
    # some field

    def __unicode__(self):
        return self.user.email

这样我会设置AUTH_PROFILE_MODULE = 'accounts.UserProfile' 并解决它的问题。但这看起来行不通,因为 python 中的继承是从左到右工作的,IndivProfile 中的所有变量都将占主导地位。

当然,我总是可以拥有一个模型,其中 IndivProfileCorpProfile 变量都混合在一起,然后我会在必要时使用所需的模型。但这对我来说看起来并不干净,我宁愿将它们隔离并在适当的地方使用适当的模型。

干净的方法有什么建议吗?

【问题讨论】:

inheritance 呢? 我可以将UserProfile抽象化并让IndivProfileCorpProfile继承自UserProfile。这仍然不能解决AUTH_PROFILE_MODULE 的问题。它会指向哪一个? 如何将企业+个人+帐户类型字段添加到一个模型中?我认为如果你只有两种类型可能没问题,但如果你有超过 2 种或者这些配置文件非常不同,则可能会很糟糕。 这不能解决user 对每种类型都不同的问题。请阅读帖子,我已经提到我可以做到,但我正在寻找一种干净的方法。 一个小问题:如果您有多个用户与同一个公司资料相关,您不能在公司资料上使用ForeignKey 字段对其进行建模。 【参考方案1】:

值得尝试使用直通字段。它背后的想法是将 UserProfile 模型用作 CorpProfile 或 IndivProfile 模型的直通模型。这样,只要将公司或个人资料链接到用户,就会创建它:

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.ForeignKey(User)
    profile = models.ForeignKey(Profile, related_name='special_profile')

class Profile(models.Model):
    common_property=something

class CorpProfile(Profile):
    user=models.ForeignKey(User, through=UserProfile)
    corp_property1=someproperty1
    corp_property2=someproperty2

class IndivProfile(Profile):
    user=models.ForeignKey(User, through=UserProfile, unique=true)
    indiv_property1=something
    indiv_property2=something

我认为这样应该可以设置AUTH_PROFILE_MODULE = 'accounts.UserProfile',并且每次创建链接到真实用户的 CorpProfile 或 IndivProfile 时,都会创建一个唯一的 UserProfile 模型。然后,您可以使用 db 查询或任何您想要的方式访问它。

我没有测试过这个,所以不能保证。这可能有点hacky,但另一方面我觉得这个想法很吸引人。 :)

【讨论】:

我试过运行它,但它显示invalid keyword argument 'through' 错误。我现在正在工作,无法获得确切的措辞。 糟糕,仅适用于多对多关系。现在看起来像另一个不太干净的解决方案。但我认为 Aamir 已经提出了一个非常简单的解决方案。 @marue,这个答案应该被完全删除吗?这是不正确的,似乎令人困惑。 @BasicWolf 应该删了吧。【参考方案2】:

您可以通过以下方式执行此操作。有一个配置文件,其中包含两个配置文件中必需的公共字段。您已经通过创建类 UserProfile 来完成此操作。

class UserProfile(models.Model):
    user = models.ForeignKey(User)
    # Some common fields here, which are shared among both corporate and individual profiles

class CorporateUser(models.Model):
    profile = models.ForeignKey(UserProfile)
    # Corporate fields here

    class Meta:
        db_table = 'corporate_user'

class IndividualUser(models.Model):
    profile = models.ForeignKey(UserProfile)
    # Individual user fields here

   class Meta:
        db_table = 'individual_user'

这里不涉及火箭科学。只需有一个关键字来区分公司简介或个人简介。例如。考虑用户正在注册。然后在表单上有一个字段,用于区分用户是否注册公司。并使用该关键字(请求参数)将用户保存在相应的模型中。

然后当你想检查用户的个人资料是公司还是个人时,你可以通过编写一个小函数来检查它。

def is_corporate_profile(profile):
    try:
        profile.corporate_user
        return True
    except CorporateUser.DoesNotExist:
        return False

# If there is no corporate profile is associated with main profile then it will raise `DoesNotExist` exception and it means its individual profile
# You can use this function as a template function also to use in template
% if profile|is_corporate_profile %

希望这会带你到某个地方。谢谢!

【讨论】:

不推荐使用OneToOne 而不是ForeignKey? 指定外键也与oneToOne关系有关。 没有 OneToOne 你应该写:try: profile.corporate_user_set.all()[0] 为了明确一点:OneToOneField 只是 ForeignKey(unique=True) 的 Django 内部包装器。所以 OTO 不只是有点相关,它和 ForeignKey 完全一样。 @marue 你错了! OneToOneField 不仅仅是 ForeignKey(unique=True) 的内部包装,这表明它们是等价的......它们不是! ***.com/a/5891861/2722398【参考方案3】:

我是这样做的。

PROFILE_TYPES = (
    (u'INDV', 'Individual'),
    (u'CORP', 'Corporate'),
)

# used just to define the relation between User and Profile
class UserProfile(models.Model):
    user = models.ForeignKey(User)
    profile = models.ForeignKey('Profile')
    type = models.CharField(choices=PROFILE_TYPES, max_length=16)

# common fields reside here
class Profile(models.Model):
    verified = models.BooleanField(default=False)

我最终使用了一个中间表来反映两个抽象模型之间的关系,User 已经在 Django 中定义,我的Profile 模型。如果有不常见的属性,我将创建一个新模型并将其关联到Profile

【讨论】:

您是如何存储不常见字段的?你能展示一下代码吗? 近 4 年后回头看 - 你有什么不同的做法吗?

以上是关于Django - 多个用户配置文件的主要内容,如果未能解决你的问题,请参考以下文章

django 如果在多个app使用各自的用户多认证

Django - 在用户创建时创建用户配置文件

如何在管理界面中内联编辑 django 用户配置文件?

Django - 不同类型的用户配置文件

Django:用户配置文件的动态 URL

如何使用 Django 显示用户配置文件? [关闭]