在Django 1.5/1.6中设置两种不同类型的用户

11

请注意——这是我关于这个主题的一个更新版本,起初的问题可以在我的原始问题中找到。但随着Django处理用户和身份验证方式的变化,这个问题再次值得提出。

我正在制作一个网站,其中有两种非常不同类型的用户,让我们称它们为“客户”和“商家”。他们都在网站上注册,但具有非常不同的功能。客户只拥有一个简单的个人资料,并可以在喜欢的商店之间购物。商家只有一个帐户,但可以访问多个商店,每个商店可以有多个商家

模型的确切细节并不重要,但这两种用户类型需要非常不同的字段。模型理想情况下应该如下所示:

Customer
  email (username)
  password
  name
  address
  time_zone
  preferred_shipping
  favorite_stores (many-to-many field)
  ...

Store Owner
  email (username)
  password
  name
  balance
  stores_owned (many-to-many field on Stores)
  stores_managed (many-to-many field on Stores)
  ...

最初,由于Django的用户自定义支持不足,我创建了一个名为UserProfile的类,其中包含一些附加字段并在User上使用了OneToOne,然后创建了额外的CustomerStoreOwner类,它们都与UserProfileOneToOne关系。但这种方式并不理想。

考虑到Django 1.5/1.6的更新,我正在尝试找到最佳结构方式。目前,我的方案如下:

class CustomerUser(AbstractBaseUser):
    ...

class StoreOwnerUser(AbstractBaseUser):
    ...

但由于存在两种类型的用户,我不能将AUTH_USER_MODEL设置为其中的一种。

最佳结构方式是什么,可以让我拥有具有不同字段的两种不同类型的用户,而不会在用户身份验证、用户创建或管理员方面引起任何问题?

另外,我如何仅通过登录就能确定该用户是CustomerUser还是StoreOwnerUser


1
您可能想创建一个基本用户,添加一个布尔标志,表示用户是客户还是商店所有者,并使用一对一关系附加另一个模型,即个人资料。 - user1876508
1
离这个问题被提出已经快一年了,但是我发现自己处于一个类似的情况。问题是:你最终采取了什么方法?另外,你考虑过店主可能想以顾客身份注册(使用相同的电子邮件地址)的情况吗?你的设计如何满足这种情况?最后,你是否考虑过为店主和顾客设置不同的登录界面(这可以帮助轻松区分登录用户类型)? - Hari Mahadevan
3个回答

5

看起来您的用户类型有一些共同特点和不同特点。如果您的用户类型具有Django默认的User模型无法直接支持的共同特点,则应直接对其进行子类化。

将额外的、不常见的特性添加到您的用户类型中最好不要通过子类化来实现,而是使用配置文件。我这样做的原因是因为这些用户类型的身份验证并没有根本性的变化,但是根据用户类型的不同,用户的详细信息会有所不同。为了适应这种情况,您可以创建一个带有这些详细信息的单独模型,并将您的User类作为OneToOne/ForeignKey关系引用(取决于您的设计)。

您可以修改用户创建过程以确定它应该是哪种用户类型,并将其相关的OneToOneField/ForeignKey(取决于您的设计)设置为相应的客户类型模型。

通过这种方式,您应该只有一个AUTH_USER_MODEL,并且您应该能够处理不同客户类型的详细信息。


谢谢,这很有道理。但是我如何从登录中知道登录的用户是“StoreOwner”还是“Customer”?在基本的“UserProfile”类中,我会有一个“storeowner_or_customer”字段,或者类似的东西吗? - jdotjdot
类似这样。UserProfile 必须对用户可用,并且每次创建用户时都要设置它。我建议您将两个配置文件模型作为两个用户类型(StoreOwner/Customer),然后可以向您的 User 模型添加一个“type”字段,这两个用户类型模型通过 OneToOne 关系引用该字段。在您的代码中,首先检查类型(即 user_obj.type == "Customer" 或类似的内容),如果为真,则可以直接访问相关详细信息 user_obj.customer.address。 - tsurantino

3
这个问题的最佳解决方法是什么,以便我可以拥有两种不同类型的用户,具有不同的字段,而不会在用户认证、用户创建或管理员方面引起任何问题?
实际上,您只有一种类型的用户。只是一些用户设置了特定的属性,而其他用户没有。考虑django中的“users”和“admins”。它们是相同模型的实例,但具有不同的属性和权限。
您应该采用类似的方法。为整个应用程序设计一个用户模型。您可以在自定义用户类中设置属性/方法来确定此用户设置了哪些标志(这将确定存在的“用户类型”)。
此外,如何仅通过登录就能告诉我这个用户是“CustomerUser”还是“StoreOwnerUser”?
您可以使用user_passes_test装饰器,它接受一个函数名称作为参数,并且仅在该函数返回真值时处理视图。

我非常喜欢那个想法,但是这样会不会导致模型中有大量未使用的字段?这方面有什么影响,特别是对于表单生成? - jdotjdot
不需要,特别是如果你正确使用模型的反向关系。例如,你不需要 stores_ownedstores_managed 字段,因为你可以使用 ORM 获取这些信息。例如,你可以在 User 模型中有一个方法,返回“管理的商店”数量,方法为 self.stores_set.count();如果你要在管理界面中显示它,则该方法是必须的,否则它只是一个值,应该保存在缓存中。 - Burhan Khalid

1
  1. Create a BaseUser which extends Django's Abstract base User
  2. Create two Sub Classes Named CustomerUser and StoreOwnerUser which extends BaseUser

    from django.db import models
    from django.contrib.auth.models import AbstractUser
    
    class BaseUser(AbstractUser):
        # all the common fields go here, for example:
        email = models.EmailField(max_length=10,unique=True)
        name = models.CharField(max_length=120)
    
    class StoreOwnerUser(BaseUser):
        # All Store Owner specific attribute goes here
        balance = models.some_balance_field()
        stores_owned = models.some_stores_owned_field()
    
        class Meta:
        verbose_name = 'Store Owner'
    
    class CustomerUser(BaseUser):
        # All Customer specific attribute goes here
        customer_id = models.CharField(max_length=30, unique=True)
        address =  models.some_address
        time_zone = models.something...
        ...
    
        class Meta:
            verbose_name = 'Customer'
    

4
AUTH_USER_MODEL 应该指定为什么?在登录时:user = authenticate(username=username, password=password)authenticate 函数会从哪个表格(CustomerUserStoreOwnerUser)中进行检查? - Sibtain
你可以实现这个功能:https://dev59.com/s10a5IYBdhLWcg3wTHBt - Saber Solooki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接