使用Django 1.5实现多个用户类型

gjb*_*gjb 37 django django-models django-1.5

使用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)
  # ...
Run Code Online (Sandbox Code Playgroud)

将多表继承与可配置用户模型结合使用是否有任何问题?

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)
  # ...
Run Code Online (Sandbox Code Playgroud)

此方法需要一些依赖于条件验证user_type.

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

此外,在案例编号1中,如何过滤用户?

谢谢.

bor*_*ges 29

警告:Django 1.5非常新,人们仍在调查其新功能.基于最近的研究回答这个问题,我的回答只不过是我的意见.

两种方式都是实现结果的有效方式,有其优点和缺点.

让我们从:

第二种选择

  • 没有嵌套模型而不是模块化.AbstractBaseUser顾名思义,它是一个抽象模型,没有特定的表格
  • 有未使用的字段
  • 您需要使用使用额外字段的模型检查user_type以进行任何迭代:

    def foo():
        if user.user_type == 'Private':
            # ...
        else:
            # ...
    
    Run Code Online (Sandbox Code Playgroud)

生成的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
);
Run Code Online (Sandbox Code Playgroud)

第一种选择

  • 具有逻辑实体分离的嵌套模型
  • 很瘦
  • 如果要使用类似函数,必须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
);
Run Code Online (Sandbox Code Playgroud)

*想象一下以下情况:

>>> 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>]
Run Code Online (Sandbox Code Playgroud)

因此,您无法通过使用直接检索子类实例BaseUser.objects.all().杰夫有一篇很棒的博客文章,更好地解释了如何从BaseUser孩子们那里完成"自动垂头丧气" .

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

  • [django-models-utils](https://github.com/carljm/django-model-utils)可以帮助继承.请参阅@ThibaultJ答案:http://stackoverflow.com/a/8502185/842935,从查询集自动向下转换模型 (2认同)
  • 而不是`if user.user_type =='Private':`你可以使用名称`is_private_user`定义`@ property`并使用`if user.is_private_user:`.对于相同目的的嵌套模型,您应该使用`isinstance()`来检查用户的类型,但同样,通过实现`@ property`可以实现相同的功能. (2认同)

小智 6

也许你应该考虑AbstractUser?