Django 上的用户角色模式
Posted
技术标签:
【中文标题】Django 上的用户角色模式【英文标题】:User roles schema on Django 【发布时间】:2016-03-16 17:57:24 【问题描述】:一个很棒的问候社区
我的问题与 Django 中管理用户和模式用户的类型有关,一开始我向你道歉,以防我的问题太“新手”或毫无意义,我开始与我相关使用 Django 用户模式及其在项目中的不同工作可能性。
我有以下情况。
我正在构建一个应用程序,其中我将拥有三种不同的用户类型:
医疗 病人 物理治疗师我正在使用默认的 Django 身份验证方案 (django.contrib.auth)。
最初,我确实认为在这个实体方案中,用户表是 auth_user
表,Django 保存创建的用户:
我在 User 表中有 is_patient
、is_medical
和 is_physiotherapist
字段,例如布尔属性。
就像一个特定的细节,我知道在 Django 默认模型中,用户是不可能修改或添加属性或字段的。
这是我无法在 User 表中添加 is_patient
、is_medical
和 is_physiotherapist
布尔字段的一个重要而有力的原因。
一个经典的建议是使用 Userprofile 表扩展用户模型,在该表中我通过 OneToOne 关系向用户模型添加字段或属性。基本示例如下:
通过这种方式,我在 Django 中的用户可以拥有现场照片并在给定时刻上传一张...
利用之前的优势,
以下架构可以适合或替代管理用户角色(patient
、medical
和 physiotherapist
用户类型)?
我将有以下关系:
用户医疗和用户患者
用户物理治疗师和用户患者
它们与其他表之间也是如此......
采用这种方法,这些关系不会受到影响吗?
不同的用户将被保存在 Users 和 UserProfile 表之间。 这是可扩展性意义上的好习惯吗?我的表可能崩溃或我的数据库?
此外,我还看到了其他替代方案,例如:
-
角色表/模型
我将有一个独立或独立的角色表/模型,这可以与 Django 用户模型相关(例如,一个用户可以有多个角色) 当我想存储特定角色的专有信息时,这种方法很有用?
-
Django Permissions and Authorization
我忽略或不知道让我工作的粒度等级。在我看到的单一方式中,权限和授权系统让我可以使用创建、编辑和删除操作....
在这里,我可以看到组创建吗? 例如一个医疗组并为其分配权限并将此权限链接到组成该组的用户?这是另一个不错的选择吗? 这个选项似乎更单一,虽然我不知道用户是否可以根据具有...的组权限进行一些操作我不知道这种想法是否正确/正确
-
AUTH_USER_MODEL Creating a Custom User model
我对患者、医疗和物理治疗师用户的要求,需要构建自定义用户模型吗?
【问题讨论】:
嘿,我的回答有什么遗漏或不满意吗? :) 很高兴能得到一些反馈! @Ire,您的回复对我非常有用。在其他一些方向上,我确实选择自定义我的用户模型并将其与 OneToOne 关系中的 Medic、Patient、Physio 模型查看这些数字cldup.com/lqB3367kAp.png - cldup.com/jxVsgfneGb.png) 当我在用户中添加属性时,我已经自定义了我的管理员表格出现在那里。 @Ire,当您说:“拥有自定义模型和组将是多余的并且使您的应用程序更难维护时,我有点不明白。”事实上,我还没有尝试过授权过程,但我同意你创建组并请求特定用户(患者、医疗或理疗师)是否存在并属于一个组...... 为什么最好像下面显示的那样明确地执行它“(这样您访问该对象中不存在的属性的可能性较小!)”而不是使用 AbstractUser 子类化 User 模型? 【参考方案1】:在这种情况下,特别是如果您想为患者、医生和物理治疗师存储不同的信息,您可以为每个人创建一个模型,并为每个用户模型创建一个 OneToOne 字段。
class Medic(models.Model):
user = models.OneToOneField(User, primary_key=True)
# other fields
class Physio(models.Model):
user = models.OneToOneField(User, primary_key=True)
# other fields
class Patient(models.Model):
user = models.OneToOneField(User, primary_key=True)
# other fields
通过这种方式,您可以在应用程序逻辑中为每种类型的用户隐含地赋予不同的权限/角色(如果您在特殊情况下需要它们,例如 ChiefMedical...,仍然使用 Django 提供的组和权限)。
您必须为您的应用程序逻辑定义一些方法,例如
def user_is_patient(user):
...
如果您遵循这条道路,最好进行良好的测试,以确保您不会遇到意外的事情,例如作为医生和物理师的用户......
Django 还允许您子类化用户模型。在幕后它会和上面的代码做同样的事情,所以最好像上面显示的那样明确地做它(这样你访问该对象中不存在的属性的可能性就会降低!)
利用前面的优势,以下模式可以适合或替代管理用户角色(患者、医疗和物理治疗师用户类型)?
您显示的架构不是很好,因为它使您将所有用户类型的信息存储在同一个表中(并且具有相同的字段)。例如,Medics 和 Physios 将有一个可能不会定义的血型字段类型,例如患者。
不同的用户将被保存在 Users 和 UserProfile 表之间。这是可扩展性意义上的好习惯吗?我的表可能崩溃或我的数据库?
这个解决方案应该没有可扩展性问题(只要您每天没有数百万个新条目写入),并且您始终可以在更远的点优化数据库。但是,您必须确保您的应用不接受“禁止”条目(例如,没有 Medic、Physio 或 Patient 个人资料的用户)
在这里,我可以看到组创建吗?例如一个医疗组并为其分配权限并将此权限链接到组成该组的用户?这是另一个不错的选择吗?这个选项似乎更单一,虽然我不知道用户是否可以根据具有...的组权限进行一些操作我不知道这种想法是否正确/正确
您可以(应该)使用 Django 的权限系统为您的用户授予权限。您可以使用它们为同一类型的用户授予不同的权限(例如,拥有比其他人更多权限的 Medics……或拥有首席理疗师群组……)
Django 允许您将权限分配给组。
但我不认为组可以替换每个用户的自定义模型,因为您想为他们存储信息。拥有自定义模型和组将是多余的,并且会使您的应用更难维护。
我对患者、医疗和物理治疗师用户的要求,需要构建自定义用户模型吗?
此选项不会很好(除非它是您唯一的选择),因为您的应用程序将无法重复使用,并且您可能还会遇到某些包的问题。
【讨论】:
【参考方案2】:您可以创建或不创建自定义用户模型,在任何情况下,您都可以使用三个单独的模型来存储相关数据,具体取决于用户是患者、医疗人员、物理治疗师还是这些的任意组合。
如果您的权限方案仅由角色(患者、医疗、物理治疗师)决定,那么您不需要使用 Django 的权限系统,因为您知道任何用户的角色,并且在最坏的情况下您可以场景,硬编码授权规则。
【讨论】:
【参考方案3】:我看了一眼问题的 cmets 并查看了一些问题:
()
我意识到您的用户模型与原始数据模型不匹配,因为在用户模型中有 get_medical_profile
、get_patient_profile
和 get_physiotherapist_profile
函数,您假设任何用户都可以同时拥有多个配置文件时间,这既没有反映在您使用 OneToOneField 的个人资料模型(医疗、患者和物理治疗师)中,也没有反映在问题的原始数据模型中,这对于抽象和类责任很重要。要求(根据下面的模型)似乎是说“一个用户只能拥有一个配置文件”。
所以.. 我认为这可以用一种简单明了的方式解决,您不需要涉及整体身份验证问题,如组和权限或向用户模型添加其他属性:
class UserProfile(models.Model):
user = models.OneToOneField(User)
# common fields shared by medical, patient and physiotherapist profiles
class MedicalUser(models.Model):
profile = models.OneToOneField(UserProfile)
# medical fields here
class PatientUser(models.Model):
profile = models.OneToOneField(UserProfile)
# patient fields here
class PhysiotherapistUser(models.Model):
profile = models.ForeignKey(UserProfile)
# patient fields here
如您所见,您可以拥有一个包含所有配置文件共享的公共字段的配置文件。每个配置文件都有一个特定的模型。
另外,您可以通过下面这个小功能检查用户是否医疗,如果没有与profile关联的医疗档案,则会引发异常,这意味着它是一个未指定的档案:
def is_medical_profile(profile):
try:
profile.medical_user
return True
except:
return False
您也可以通过这种方式在模板中使用它(作为自定义模板标签):
% if profile | is_medical_profile %
使用这种方法您无需设置 AUTH_USER_MODEL
我希望这会改进您的解决方案。
补充说明:
如果您决定使用自定义用户模型,请设置 settings.AUTH_USER_MODEL 并将其用作用户的外键。
在一篇很棒的书Two scoops of Django上说:
从 Django 1.5 开始,官方首选的附加方式 ForeignKey、OneToOneField 或 ManyToManyField 到用户
因此,您的用户配置文件模型将更改如下:
from django.conf import settings
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
是的,它看起来有点奇怪,但这是 Django 官方文档的建议。
【讨论】:
感谢您的建议和最佳实践:D。你的方法很棒!尽管即使我在我的数据模型中指示 OneToOneField 关系,用户也可能有许多配置文件(医疗、物理治疗师和医疗)。在帖子下面我在cli中做了一些测试【参考方案4】:@geoom @Ire @lorenzo-peña 我通过 Django 管理站点创建了一个用户,并通过 python shell 检查了他们的属性(is_medical、is_patient、is_physiotherapy)
In [6]: User.objects.filter(username='agarcial').values('is_medical','is_patient','is_physiotherapist')
Out[6]: ['is_physiotherapist': True, 'is_patient': True, 'is_medical': True]
目前在我的views.py中,我正在这样做,只有当这是三种用户类型(医疗、患者或物理治疗师)之一时,用户才登录
# Create your views here.
class ProfileView(LoginRequiredMixin, TemplateView):
template_name = 'profile.html'
def get_context_data(self, **kwargs):
self.request.session['Hi'] = True
context = super(ProfileView, self).get_context_data(**kwargs)
is_auth = False
name = None
# Check if in the request goes the user
user = self.request.user
# Check about of possible cases (For now is one profile)
if user.is_medical:
#if self.request.user.is_authenticated():
print (user.is_medical)
is_auth = True
profile=user.get_medical_profile()
#name = self.request.user.username
data =
'is_auth':is_auth,
'profile':profile,
context.update('userprofile':profile, 'data':data)
elif user.is_patient:
print (user.is_patient)
is_auth=True
profile=user.get_patient_profile()
data =
'is_auth':is_auth,
'profile':profile,
context.update('userprofile':profile,'data':data)
elif user.is_physiotherapist:
print (user.is_physiotherapist)
is_auth=True
profile=user.get_physiotherapist_profile()
data =
'is_auth':is_auth,
'profile':profile,
context.update('userprofile':profile,'data':data)
return context
def get_userprofile(self):
return self.request.user.userprofile
如果我检查其他可能的组合(用户患者、医疗和物理治疗师),这可能有效吗?
我认为为(医疗、患者、物理治疗师)创建组并为授权主题绑定用户,尽管我应该查看授权过程的其他内容,例如 django guardian?
这个怎么样?
【讨论】:
以上是关于Django 上的用户角色模式的主要内容,如果未能解决你的问题,请参考以下文章