【问题标题】:User roles schema on DjangoDjango 上的用户角色模式
【发布时间】: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 表之间。 这是可扩展性意义上的好习惯吗?我的表可能崩溃或我的数据库?


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

  1. 角色表/模型

我将有一个独立或独立的角色表/模型,这可以与 Django 用户模型相关(例如,一个用户可以有多个角色) 当我想存储特定角色的专有信息时,这种方法很有用?

  1. Django Permissions and Authorization

我忽略或不知道让我工作的粒度等级。在我看到的单一方式中,权限和授权系统让我可以使用创建、编辑和删除操作....

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

  1. AUTH_USER_MODEL Creating a Custom User model

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

【问题讨论】:

  • 嘿,我的回答有什么遗漏或不满意吗? :) 很高兴能得到一些反馈!
  • @Ire,您的回复对我非常有用。在其他一些方向上,我确实选择自定义我的用户模型并将其与 OneToOne 关系中的 Medic、Patient、Physio 模型查看这些数字cldup.com/lqB3367kAp.png - cldup.com/jxVsgfneGb.png) 当我在用户中添加属性时,我已经自定义了我的管理员表格出现在那里。
  • @Ire,当您说:“拥有自定义模型和组将是多余的并且使您的应用程序更难维护时,我有点不明白。”事实上,我还没有尝试过授权过程,但我同意你创建组并请求特定用户(患者、医疗或理疗师)是否存在并属于一个组......
  • 为什么最好像下面显示的那样明确地执行它“(这样您访问该对象中不存在的属性的可能性较小!)”而不是使用 AbstractUser 子类化 User 模型?

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


【解决方案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

      这个怎么样?

      【讨论】:

        猜你喜欢
        • 2017-03-17
        • 2015-08-15
        • 2019-11-16
        • 2016-01-31
        • 2016-12-12
        • 1970-01-01
        • 2019-02-21
        • 1970-01-01
        • 2011-01-22
        相关资源
        最近更新 更多