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_patientis_medicalis_physiotherapist 字段,例如布尔属性。

就像一个特定的细节,我知道在 Django 默认模型中,用户是不可能修改或添加属性或字段的。

这是我无法在 User 表中添加 is_patientis_medicalis_physiotherapist 布尔字段的一个重要而有力的原因。

一个经典的建议是使用 Userprofile 表扩展用户模型,在该表中我通过 OneToOne 关系向用户模型添加字段或属性。基本示例如下:

通过这种方式,我在 Django 中的用户可以拥有现场照片并在给定时刻上传一张...

利用之前的优势, 以下架构可以适合或替代管理用户角色(patientmedicalphysiotherapist 用户类型)?

我将有以下关系:

用户医疗和用户患者

用户物理治疗师和用户患者

它们与其他表之间也是如此......

采用这种方法,这些关系不会受到影响吗?

不同的用户将被保存在 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_profileget_patient_profileget_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 上的用户角色模式的主要内容,如果未能解决你的问题,请参考以下文章

Django:实现多个用户级别/角色/类型

django之权限组件

按用户角色和 id 过滤的 Django 自定义权限

根据用户角色获取登录用户的django权限以显示/隐藏菜单

如何在 Django 中按应用程序处理用户和角色

Django Postgresql Heroku:操作错误-'角色“用户名”的连接太多'