使用 Django 1.5 实现多种用户类型
Posted
技术标签:
【中文标题】使用 Django 1.5 实现多种用户类型【英文标题】:Implementing multiple user types with Django 1.5 【发布时间】:2012-11-21 21:49:21 【问题描述】:使用 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) 使用具有“类型”属性的单个模型
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 种情况,我该如何过滤我的用户?
谢谢。
【问题讨论】:
【参考方案1】:警告: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
);
第一选择
具有实体逻辑分离的嵌套模型 很瘦 你必须为每个孩子实现BaseUserManager
如果你想使用create_user
-like函数
您无法使用简单的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 有一个excellent blog post 更好地解释了如何完成从BaseUser
到它的孩子的“自动向下转换”。
也就是说,您应该考虑每种方法的优缺点以及它们对您的项目的影响。当涉及的逻辑很小(如示例中所述)时,两种方法都有效。但在更复杂的情况下,一种方法可能比另一种更好。我会选择多模型选项,因为它更具可扩展性。
【讨论】:
优秀的答案。自动向下铸造正是我所缺少的。我将选择选项 1 并实施它。非常感谢。 django-models-utils 可以帮助继承。请参阅@ThibaultJ 答案:***.com/a/8502185/842935,从查询集中自动向下转换模型 您可以用名称is_private_user
定义@property
并使用if user.is_private_user:
,而不是if user.user_type == 'Private':
。对于相同目的的嵌套模型,您应该使用isinstance()
来检查用户的类型,但同样,同样的功能可以通过实现@property
来实现【参考方案2】:
也许您应该考虑 AbstractUser?
【讨论】:
【参考方案3】:您只能将一个模型分配给 AUTH_USER_MODEL 的新自定义用户模型。使用多表继承,您有两个模型。所以这是一个问题。
在涵盖两种用户类型的单个用户模型的情况下,您可以抽象模型方法中的条件逻辑。您还可以根据不同的用户类型为不同的用户类型使用不同的管理器。这也可以帮助您在处理特定用户类型时更加明确。
其他选项可能是仅将最常见的属性存储在单个用户模型中,然后将两种用户类型的细节附加到它们自己的表中,这些表链接到您的主用户表。
如果两个用户有大部分共同点(至少在数据方面),我会将它们放在一个地方。最后,我会考虑什么更简单,更容易维护。
【讨论】:
感谢您的回答。在上面的示例中,BaseUser
包含身份验证所需的所有字段,因此将分配给AUTH_USER_MODEL
。我完全赞成让事情尽可能简单,但我也在努力避免对数据库进行非规范化。
如果两种用户类型只有 1 或 2 个字段不同,我看不出规范化有多大优势。但你是对的,你可以将 BaseUser 用于 AUTH_USER_MODEL。我不知道向下转换,你的第一个案例更有意义。【参考方案4】:
我会使用带有“类型”属性的单个模型。原因如下:
只有一张桌子,只有一种型号 如果您想从一种类型转换为另一种类型,只需更改属性 为一种类型存在而另一种类型不存在的字段实现 getter 和 setter = 更易于使用。【讨论】:
以上是关于使用 Django 1.5 实现多种用户类型的主要内容,如果未能解决你的问题,请参考以下文章