37

使用 Django 1.5 新的可配置用户模型功能实现多种用户类型的推荐方法是什么?

我想要两种用户类型:私人用户和交易用户,每个用户都有自己的一组必填字段。

我可以考虑两种方法来实现这一点:

1)多表继承

class BaseUser(AbstractBaseUser):
  email = models.EmailField(max_length=254, unique=True)
  # ...


class PrivateUser(BaseUser):
  first_name = models.CharField(max_length=30)
  last_name = models.CharField(max_length=30)
  # ...


class TradeUser(BaseUser):
  company_name = models.CharField(max_length=100)
  # ...

将多表继承与可配置用户模型结合使用有什么问题吗?

2)使用具有“类型”属性的单个模型

class User(AbstractBaseUser):
  email = models.EmailField(max_length=254, unique=True)
  user_type = models.CharField(max_length=30, choices={
    'P': 'Private',
    'T': 'Trade',
  })
  first_name = models.CharField(max_length=30, blank=True)
  last_name = models.CharField(max_length=30, blank=True)
  company_name = models.CharField(max_length=100, blank=True)
  # ...

这种方法需要一些依赖于user_type.

这些方法中的哪一种最适合我的用例?或者也许有更好的方法来实现这一目标?

另外,在第 1 种情况下,我如何过滤我的用户?

谢谢。

4

4 回答 4

29

警告:Django 1.5 非常新,人们仍在研究它的新功能。所以我的回答无非是我的意见,基于最近的研究来回答这个问题。

这两种方式都是实现结果的有效方式,各有优缺点。

让我们从:

第二种选择

  • 没有嵌套模型,也没有模块化。AbstractBaseUser,顾名思义,是一个抽象模型,没有具体的表
  • 有未使用的字段
  • 您需要使用使用额外字段的模型检查 user_type 是否有任何迭代:

    def foo():
        if user.user_type == 'Private':
            # ...
        else:
            # ...
    

生成的 SQL 大致如下:

CREATE TABLE "myapp_user" (
    "id" integer NOT NULL PRIMARY KEY,
    "password" varchar(128) NOT NULL,
    "last_login" datetime NOT NULL,
    "email" varchar(254) NOT NULL UNIQUE,
    "user_type" varchar(30) NOT NULL,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL,
    "company_name" varchar(100) NOT NULL
);

第一个选项

  • 具有实体逻辑分离的嵌套模型
  • 很瘦
  • 如果要使用-like 函数,则必须BaseUserManager为每个孩子实现 create_user
  • 您不能使用简单的BaseUser.objects.all()*访问子类

生成的 SQL 大致如下:

CREATE TABLE "myapp_baseuser" (
    "id" integer NOT NULL PRIMARY KEY,
    "password" varchar(128) NOT NULL,
    "last_login" datetime NOT NULL,
    "email" varchar(254) NOT NULL UNIQUE
);

CREATE TABLE "myapp_privateuser" (
    "baseuser_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "myapp_baseuser" ("id"),
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);

CREATE TABLE "myapp_tradeuser" (
    "baseuser_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "myapp_baseuser" ("id"),
    "company_name" varchar(100) NOT NULL
);

* 想象以下情况:

>>> BaseUser.objects.create_user('baseuser@users.com', password='baseuser')
>>> PrivateUser.objects.create_user('privateuser@users.com', password='privateuser', first_name='His', last_name='Name')
>>> TradeUser.objects.create_user('tradeuser@users.com', password='tradeuser', company_name='Tech Inc.')
>>> BaseUser.objects.all()
[<BaseUser: baseuser@users.com>, <BaseUser: privateuser@users.com>, <BaseUser: tradeuser@users.com>]
>>> PrivateUser.objects.all()
[<PrivateUser: privateuser@users.com>]
>>> TradeUser.objects.all()
[<TradeUser: tradeuser@users.com>]

因此,您不能直接使用BaseUser.objects.all(). Jeff有一篇出色的博客文章,更好地解释了如何实现“自动向下转换” BaseUser

也就是说,您应该考虑每种方法的优缺点及其对项目的影响。当涉及的逻辑很小(如示例中所述)时,两种方法都有效。但在更复杂的情况下,一种方法可能比另一种更好。我会选择多模型选项,因为它更具可扩展性。

于 2012-12-06T21:48:43.103 回答
6

也许你应该考虑 AbstractUser?

于 2013-01-24T13:11:24.683 回答
2

您只能将一个模型分配给 AUTH_USER_MODEL 的新自定义用户模型。使用多表继承,您有两个模型。所以这是一个问题。

在涵盖两种用户类型的单个用户模型的情况下,您可以抽象模型方法中的条件逻辑。您还可以根据不同的用户类型为不同的用户类型使用不同的管理器。这也可以帮助您在使用特定用户类型时变得明确。

其他选项可能是仅将最常见的属性存储在单个用户模型中,然后将两种用户类型的细节附加到它们自己的表中,这些表链接到您的主用户表。

如果两个用户有大部分共同点(至少在数据方面),我会把它们放在一个地方。最后,我会考虑什么更简单,更容易维护。

于 2012-12-06T20:59:43.327 回答
1

我会使用具有“类型”属性的单个模型。原因如下:

  • 只有一张桌子,只有一种型号
  • 如果要从一种类型转换为另一种类型,只需更改属性
  • 为一种类型存在而其他类型不存在的字段实现 getter 和 setter = 使用起来更简单。
于 2013-04-19T13:32:57.133 回答