What is the recommended way to implement multiple user types using Django 1.5's new configurable user model functionality?
使用Django 1.5的新可配置用户模型功能,推荐的实现多个用户类型的方法是什么?
I would like to have two user types: private users and trade users, each with their own set of required fields.
我希望有两种用户类型:私有用户和交易用户,每个用户都有自己所需的字段集。
There are two ways I can think to implement this:
我认为有两种方法可以实现这一点:
1) Multi-table inheritance
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)
# ...
Are there any problems with using multi-table inheritance in conjunction with the configurable user model?
与可配置用户模型一起使用多表继承是否存在问题?
2) Using a single model with a "type" attribute
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)
# ...
This method would require some conditional validation dependent upon user_type
.
这个方法需要一些依赖于user_type的条件验证。
Which of these methods best suits my use case? Or perhaps there is a better way of achieving this?
这些方法中哪一种最适合我的用例?或者也许有更好的方法来实现这个目标?
Also, In case number 1, how can I filter my users?
另外,在第一种情况下,我如何过滤我的用户?
Thanks.
谢谢。
4 个解决方案
#1
29
Warning: Django 1.5 is very new and the people are still investigating its new features. So my answer is nothing more than my opinion, based on recent research to answer this question.
警告:Django 1.5非常新,人们还在研究它的新特性。所以我的答案就是我的观点,基于最近的研究来回答这个问题。
Both ways are valid ways to achieve the result, with its advantages and disadvantages.
这两种方法都是实现结果的有效方法,各有利弊。
Let's start with the:
让我们开始:
Second option
第二个选项
- Without nested models and not modular.
AbstractBaseUser
, as the name says, is an abstract model and does not have a specific table - 没有嵌套模型,没有模块化。AbstractBaseUser,顾名思义,是一个抽象模型,没有特定的表。
- Has unused fields
- 有未使用的字段
-
You need to check the user_type for any iteration with the model that uses the extra fields:
您需要检查user_type对于使用额外字段的模型的任何迭代:
def foo(): if user.user_type == 'Private': # ... else: # ...
The resulting SQL would be approximately as follows:
所得到的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
第一个选项
- Nested models with logical separation of entities
- 具有实体逻辑分离的嵌套模型
- Very lean
- 很瘦
- You must implement
BaseUserManager
for each child if you want to usecreate_user
-like functions - 如果希望使用create_user类函数,则必须为每个子代实现BaseUserManager
- You cannot access the subclasses with a simple
BaseUser.objects.all()
* - 不能使用简单的BaseUser.objects.all()*访问子类
The resulting SQL would be approximately as follows:
所得到的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
);
* Imagine the following situation:
想象以下情况:
>>> 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>]
So, you cannot directly retrieve the subclasses instances by using BaseUser.objects.all()
. There is an excellent blog post by Jeff explaining better how to accomplish "automatic downcast" from BaseUser
to its childs.
因此,不能通过使用BaseUser.objects.all()直接检索子类实例。Jeff有一篇很好的博文,解释了如何从BaseUser到它的childs实现“自动downcast”。
That said, you should consider the advantages and disadvantages of each approach and their impact on your project. When the involved logic is small (as in the example described), both approaches are valid. But in a more complex scenario, an approach can be better than the other one. I would choose the multi model option because it is more extensible.
也就是说,您应该考虑每种方法的优缺点及其对项目的影响。当涉及的逻辑很小(如描述的示例)时,这两种方法都是有效的。但在更复杂的情况下,一种方法可能比另一种更好。我选择multimodel选项,因为它更具有可扩展性。
#2
6
Maybe you should consider AbstractUser?
也许你应该考虑一下AbstractUser?
#3
2
The new custom user model you can assign only one model to AUTH_USER_MODEL. With multi-table inheritance you have two models. So that is a problem.
新的自定义用户模型只能为AUTH_USER_MODEL分配一个模型。对于多表继承,您有两个模型。这是一个问题。
In the case of a single user model that covers both user types you could abstract the conditional logic in the model methods. You can also use different managers for different user types based on how much they are different. This could also help you in being explicit when working with a specific user type.
对于包含两个用户类型的单个用户模型,可以在模型方法中抽象条件逻辑。您还可以根据不同的用户类型使用不同的管理器。这还可以帮助您在处理特定用户类型时更加明确。
Other option could be to store only most common attributes in a single user model and then attach specifics of two user types into their own tables which are linked to your main user table.
其他选项可能是在单个用户模型中存储最常见的属性,然后将两种用户类型的细节添加到它们自己的表中,这些表与主用户表相关联。
If both users have most of the things in common (in terms of data at least), I would keep them in one place. In the end, I would think about what is simpler and easier to maintain.
如果两个用户拥有大多数相同的东西(至少就数据而言),我将把它们放在一个地方。最后,我会考虑什么更简单,更容易维护。
#4
1
I'd use a single model with a "type" attribute. Here is why:
我将使用带有“type”属性的单一模型。这里是原因:
- Only one table, only one model
- 只有一个表,只有一个模型
- If you want to convert from one type to another you just change attribute
- 如果要从一种类型转换到另一种类型,只需更改属性
- Implement getters and setters for the fields that exists for one type and doesn't exists for other = much more simple to use.
- 为一个类型存在而另一个类型不存在的字段实现getter和setter =更容易使用。
#1
29
Warning: Django 1.5 is very new and the people are still investigating its new features. So my answer is nothing more than my opinion, based on recent research to answer this question.
警告:Django 1.5非常新,人们还在研究它的新特性。所以我的答案就是我的观点,基于最近的研究来回答这个问题。
Both ways are valid ways to achieve the result, with its advantages and disadvantages.
这两种方法都是实现结果的有效方法,各有利弊。
Let's start with the:
让我们开始:
Second option
第二个选项
- Without nested models and not modular.
AbstractBaseUser
, as the name says, is an abstract model and does not have a specific table - 没有嵌套模型,没有模块化。AbstractBaseUser,顾名思义,是一个抽象模型,没有特定的表。
- Has unused fields
- 有未使用的字段
-
You need to check the user_type for any iteration with the model that uses the extra fields:
您需要检查user_type对于使用额外字段的模型的任何迭代:
def foo(): if user.user_type == 'Private': # ... else: # ...
The resulting SQL would be approximately as follows:
所得到的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
第一个选项
- Nested models with logical separation of entities
- 具有实体逻辑分离的嵌套模型
- Very lean
- 很瘦
- You must implement
BaseUserManager
for each child if you want to usecreate_user
-like functions - 如果希望使用create_user类函数,则必须为每个子代实现BaseUserManager
- You cannot access the subclasses with a simple
BaseUser.objects.all()
* - 不能使用简单的BaseUser.objects.all()*访问子类
The resulting SQL would be approximately as follows:
所得到的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
);
* Imagine the following situation:
想象以下情况:
>>> 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>]
So, you cannot directly retrieve the subclasses instances by using BaseUser.objects.all()
. There is an excellent blog post by Jeff explaining better how to accomplish "automatic downcast" from BaseUser
to its childs.
因此,不能通过使用BaseUser.objects.all()直接检索子类实例。Jeff有一篇很好的博文,解释了如何从BaseUser到它的childs实现“自动downcast”。
That said, you should consider the advantages and disadvantages of each approach and their impact on your project. When the involved logic is small (as in the example described), both approaches are valid. But in a more complex scenario, an approach can be better than the other one. I would choose the multi model option because it is more extensible.
也就是说,您应该考虑每种方法的优缺点及其对项目的影响。当涉及的逻辑很小(如描述的示例)时,这两种方法都是有效的。但在更复杂的情况下,一种方法可能比另一种更好。我选择multimodel选项,因为它更具有可扩展性。
#2
6
Maybe you should consider AbstractUser?
也许你应该考虑一下AbstractUser?
#3
2
The new custom user model you can assign only one model to AUTH_USER_MODEL. With multi-table inheritance you have two models. So that is a problem.
新的自定义用户模型只能为AUTH_USER_MODEL分配一个模型。对于多表继承,您有两个模型。这是一个问题。
In the case of a single user model that covers both user types you could abstract the conditional logic in the model methods. You can also use different managers for different user types based on how much they are different. This could also help you in being explicit when working with a specific user type.
对于包含两个用户类型的单个用户模型,可以在模型方法中抽象条件逻辑。您还可以根据不同的用户类型使用不同的管理器。这还可以帮助您在处理特定用户类型时更加明确。
Other option could be to store only most common attributes in a single user model and then attach specifics of two user types into their own tables which are linked to your main user table.
其他选项可能是在单个用户模型中存储最常见的属性,然后将两种用户类型的细节添加到它们自己的表中,这些表与主用户表相关联。
If both users have most of the things in common (in terms of data at least), I would keep them in one place. In the end, I would think about what is simpler and easier to maintain.
如果两个用户拥有大多数相同的东西(至少就数据而言),我将把它们放在一个地方。最后,我会考虑什么更简单,更容易维护。
#4
1
I'd use a single model with a "type" attribute. Here is why:
我将使用带有“type”属性的单一模型。这里是原因:
- Only one table, only one model
- 只有一个表,只有一个模型
- If you want to convert from one type to another you just change attribute
- 如果要从一种类型转换到另一种类型,只需更改属性
- Implement getters and setters for the fields that exists for one type and doesn't exists for other = much more simple to use.
- 为一个类型存在而另一个类型不存在的字段实现getter和setter =更容易使用。