使用Django 1.5新的configurable user model功能实现多种用户类型的推荐方法是什么?

我希望有两种用户类型:私有用户和贸易用户,每个用户都有自己的必填字段集.

我认为有两种方法可以实现这一点:

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)使用具有"type"属性的单个模型

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进行一些条件验证.

以下哪种方法最适合我的用例?或者也许有更好的方法来实现这一点?

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

谢谢

推荐答案

警告:Django 1.5非常新,人们还在调查它的新特性.因此,我的回答只不过是我的观点,基于最近的研究来回答这个问题.

这两种方法都是实现目标的有效方法,各有利弊.

让我们从以下内容开始:

Second option

  • 没有嵌套模型,没有模块化.顾名思义,AbstractBaseUser是一个抽象模型,没有特定表
  • 有未使用的字段
  • 对于使用额外字段的模型的任何迭代,您需要判断用户类型:

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

First option

  • 实体逻辑分离的嵌套模型
  • 非常瘦
  • 必须 for each 子级实现BaseUserManager个类似于if you want to use 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()直接检索子类实例.杰夫的"excellent blog post"更好地解释了如何实现从BaseUser到其子元素的"自动向下转换(Automatic Downcast)".

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

Django相关问答推荐

如何在Django中将可选参数传递给视图?

当使用django-tinymce时,我在哪里指定referer?

一次请求中更新整个Django模型

Django ORM:子查询上的文本聚合器

Pytest-django - 测试创建和传递所需的用户对象

Django ORM __in 但不是精确的,包含不区分大小写的?

django REST 框架 - 嵌套 ModelSerializer 的有限查询集?

Django:在模板中显示当前语言环境

在 django/python 上访问请求标头

如何在 PyCharm 中重命名 Django 元素?

如何在 django admin 中显示布尔属性

related_name 参数在 Django 模型中没有按预期工作?

如何在 Django 和 django-jsonfield 中将 JSONField 的默认值设置为空列表?

Python 社区里的小马是怎么回事?

Django - 一起为 2 个或更多字段创建唯一的数据库约束

如何重置 PostgreSQL 表上的 ID 序列

django python 日期时间设置为午夜

将 jQuery 脚本添加到 Django 管理界面

Django admin:使字段在添加中可编辑但不可编辑

Django 测试客户端方法覆盖标头