Django上的用户角色架构

时间:2015-12-10 22:42:08

标签: python django django-models user-roles django-users

一个很棒的问候社区

我的问题与Django中的管理用户和架构用户的类型有关,一开始我请你道歉,以防万一我的问题也可能会出现问题"新手"或者没有意义,我开始将我与Django用户模式及其在项目中的不同工作可能性联系起来。

我有以下情况。

我正在构建一个应用程序,其中我将有三种不同的用户类型:

  • 医疗
  • 患者
  • 物理治疗

我正在使用默认的Django身份验证方案(django.contrib.auth)。

最初,我确实在这个实体方案中考虑过,其中User表是Django保存用户创建的auth_user表:

Schema thinked (bad  - ?)

我在User表中有is_patientis_medicalis_physiotherapist字段,如布尔属性。

像特定细节一样,我理解在Django默认模型中,用户无法修改或添加属性或字段。

这是一个重要且有力的理由,我无法在用户表中添加is_patientis_medicalis_physiotherapist布尔字段。

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

Extending Django users model

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

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

Other schema thinked

我将在:

之间建立关系
  • 用户医疗和用户患者

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

等他们和其他桌子......

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

将在Users和UserProfile表之间保存不同的用户。 这是可扩展性意义上的一个好习惯吗?我的表可能是崩溃还是我的数据库?

此外,我还看到了其他替代方案,例如:

  1. 角色表/模型
  2. 我将使角色表/模型独立或分离,并且这可以与Django用户模型相关(一个用户可以通过示例具有多个角色) 当我想要在specia中存储关于角色的独家信息时,这种方法很有用吗?

    1. Django Permissions and Authorization
    2. 我忽略或不知道让我工作的粒度等级。我只看到权限和授权系统允许我使用创建,编辑和删除操作......

      在这里,我可以看到群组创作吗? 例如,医疗组并为其分配权限并将此权限链接到组成该组的用户?这是另一个好的选择吗? 这个选项似乎更单一,但我不知道用户是否可以根据群组权限进行某些操作......我不知道这种想法是否正确/正确

      1. AUTH_USER_MODEL Creating a Custom User model
      2. 我对患者,医疗和物理治疗师用户的要求需要构建自定义用户模型吗?

4 个答案:

答案 0 :(得分:6)

在这种情况下,特别是如果您想为患者,医务人员和物理治疗师存储不同的信息,您可以为每个人创建一个模型,并为每个用户模型设置一个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

通过这种方式,您可以在应用程序逻辑中为每种类型的用户隐式提供不同的权限/角色(并且仍然使用Django提供的组和权限,如果您需要特殊情况,例如ChiefMedical ......)。

您必须为您的应用程序逻辑定义一些方法,例如

def user_is_patient(user):
     ...

如果您遵循这条路径,最好进行良好的测试,以确保您不会遇到意外的事情,例如Medic和Physio的用户......

Django也允许您为用户模型创建子类。在封面下,它将与上面的代码做同样的事情,因此最好如上所示明确地执行此操作(这样,您访问该对象中不存在的属性的可能性就会降低!)< / p>

  

利用以前的模式,以下模式可以适用于管理用户角色(患者,医疗和物理治疗师用户类型),也可以作为替代方案?

您展示的架构并不是很好,因为它可以让您将所有用户类型的信息存储在同一个表中(并使用相同的字段)。例如,Medics和Physios将具有类似患者的血型字段类型,可能无法定义。

  

将在Users和UserProfile表之间保存不同的用户。这是可扩展性意义上的一个好习惯吗?我的表可能是崩溃还是我的数据库?

此解决方案不应存在可伸缩性问题(只要您每天都没有数百万条新条目写入),您可以随时优化数据库。但是,您必须确保您的应用无法接受“禁止”#39;条目(例如没有Medic,Physio或Patient个人资料的用户)

  

在这里,我可以看到群组创作吗?例如,医疗组并为其分配权限并将此权限链接到组成该组的用户?这是另一个好的选择吗?这个选项似乎更单一,但我不知道用户是否可以根据群组权限进行某些操作......我不知道这种想法是否正确/正确

您可以(应该)使用Django的权限系统为您的用户授予权限。您可以使用它们为相同类型的用户提供不同的权限(例如,具有比其他用户更多权限的Medics ......或者具有主要物理组的用户......)

Django允许您为组分配权限。

但我不认为群组可以替换每个用户的自定义模型,因为您希望为它们存储信息。拥有自定义模型和组将是多余的,并使您的应用程序更难维护。

  

我对患者,医疗和物理治疗师用户的要求需要构建自定义用户模型吗?

此选项不会很好(除非它是您唯一的选择),因为您的应用程序不会重复使用,并且您可能也遇到某些程序包的问题。

答案 1 :(得分:3)

您可以创建或不创建自定义用户模型,在任何情况下,您可以使用三个单独的模型来存储相关数据,具体取决于用户是患者,医疗,物理治疗师还是这些模型的任意组合。

如果您的权限方案完全由角色(患者,医疗,物理治疗师)决定,那么您不需要使用Django的权限系统,因为您知道任何用户的角色和在最糟糕的情况下,您可以使用硬编码授权规则。

答案 2 :(得分:2)

我瞥了一眼问题的评论,我看了一些问题:

https://cldup.com/jxVsgfneGb.png

我意识到您的用户模型与原始数据模型不匹配,因为在用户模型中有get_medical_profileget_patient_profileget_physiotherapist_profile函数,您假设任何用户都可以同时拥有多个配置文件,这些配置文件(医疗,患者和物理治疗师)既没有使用OneToOneField,也没有反映在问题的原始数据模型中,这对抽象和类责任来说非常重要。要求(根据下面的模型)似乎说“一个用户只能有一个配置文件”。

enter image description here

所以......我认为这可以通过简单明了的方式解决,您不需要像组和权限那样参与整体身份验证,也不需要为用户模型添加其他属性:

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

如您所见,您可以拥有一个包含所有配置文件共享的公共字段的配置文件。每个配置文件都有一个特定的模型。

此外,您可以通过以下这个小功能检查用户是否是医疗用户,然后如果没有与个人资料相关联的医疗档案,那么它将引发异常,这意味着它是未指定的个人资料:

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 to User

因此,您的用户个人资料模型将更改如下:

from django.conf import settings
from django.db import models

class UserProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL)

是的,它看起来有点奇怪,但这就是官方Django文档的建议。

答案 3 :(得分:0)

@geoom @Ire @ lorenzo-peña我通过Django管理站点创建了一个用户,我通过python shell检查了他们的属性(is_medical,is_patient,is_physiotherapist)

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

这个怎么样?