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

时间:2020-04-05 09:14:01

标签: python mysql django database web

我使用Django已经有一段时间了,但是直到现在我还没有想到这一点。

当前,我有一个包含不同用户级别的项目。通常,根据我过去的经验,我仅使用Django开发系统,只有两个用户级别,即超级用户和普通/常规用户。所以我的问题是在模型/数据库中呈现这些不同用户级别的有效方法是什么?在这里,我将以学校系统为例,并提供一些初步的想法。实施它。

用户级别:

  1. 管理员(超级用户和员工)
  2. 校长
  3. 老师
  4. 学生

方法1:根据每个用户级别添加新表

from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    user = models.CharfieldField(max_length = 10, unique = True)

class Admin(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)

class Pricipal(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)

class Teacher(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)

class Student(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)

方法2:在用户模型中添加其他用户类型属性

from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    user = models.CharfieldField(max_length = 10, unique = True)
    is_superuser = models.BooleanField(default = False)
    is_staff = models.BooleanField(default = False)
    is_principal = models.BooleanField(default = False)
    is_teacher = models.BooleanField(default = False)
    is_student = models.BooleanField(default = False

'''
User table in DB:
user | is_superuser | is_staff | is_principal | is_teacher | is_student
'''

我的想法:

在方法1中,由于内置的​​用户模型具有两个字段is_staff和is_superuser,是否可以如上例中那样将字段实现/更改为SuperUser / Admin表?这意味着当我创建一个admin / superuser时,我希望它在Admin表中添加新行,而不是添加新用户并将用户的is_superuser和is_staff字段更新为内置用户模型中的1。 >

在方法2中,问题在于具有不同访问权限的表直接连接到它。例如,薪金模型(学生用户无法访问)与用户模型(包含学生用户)具有直接链接。

我希望我能够获得一些见识,并且也能以适当有效的方式来实现此目的,以防止将来出现任何实现上的不便和错误。非常感谢。

3 个答案:

答案 0 :(得分:2)

我在几个项目中使用的方法之一是(伪代码):

<html>

<head>
  <title> JAVASCRIPT </title>
</head>

<body>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <script src="test.js">
  </script>
  <link rel="stylesheet" type="text/css" href="diszites.css">
  <center>
    <p id="paragraph"> <span id="number1">8</span> * <span id="number2">8</span>?
      <button id="button"> Click me! </button>
      <input type="text" id="inputfield" placeholder="Result">
      <p id="output"></p>
  </center>
</body>

</html>

然后,您可以使用此逻辑编写包装函数,以检查任何操作级别是否大于用户级别,例如:如果某人想要更改超级用户密码,则他/她应以0级用户身份登录但可以更改普通用户的密码应该为0、1级。此逻辑也可以应用于类,函数等操作。

创建基类,然后向其添加class User(AbstractUser): ADMIN = 0 PRINCIPLE = 1 TEACHER = 2 STUDENT = 3 USER_LEVEL_CHOICES = ( (ADMIN, "Admin"), (PRINCIPLE, "Principle"), (TEACHER, "Teacher"), (STUDENT, "Student"), ) user_level = models.IntgerField(choices=USER_LEVEL_CHOICES) def lvl_decorator(): def check_lvl(func): def function_wrapper(self, actor, action_on, *args, **kwargs): if 'action_lvl' not in action_on: # then action_on is user if actor.user_lvl < action_on.user_lvl: return True return False else: # then action_on is action of some kind for that user (you can add action_lvl to ... and pas them to this wapper) if actor.user_lvl < action_on.action_lvl: return True return False return function_wrapper return check_lvl ,然后从基类中固有=>这样可以使您的代码超级干净,并防止进一步的复制粘贴。

我的意思示例:

lvl_decorator

在任何需要的地方使用此基类。

答案 1 :(得分:2)

我认为您在使用方法2的道路正确。它更轻便,更直接。

我不会为每个权限级别使用自定义的“类似用户”模型。过于复杂,无法扩展,无法增加查询数量,对您的问题没有太大好处。 不是您的UML模式,但其内容必须保证您的许可要求

如果权限级别不是互斥的:

from django.db import models
from django.contrib.postgres.fields import ArrayField


class User(AbstractUser):
    ADMIN = 0
    PRINCIPLE = 1
    TEACHER = 2
    STUDENT = 3
    USER_LEVEL_CHOICES = (
        (ADMIN, "Admin"),
        (PRINCIPLE, "Principle"),
        (TEACHER, "Teacher"),
        (STUDENT, "Student"),
    )
    status = ArrayField(
        models.IntegerField(choices=USER_LEVEL_CHOICES, blank=True, default=STUDENT),
    )

但是您需要更广泛的反思。


我认为您正在谈论两个独立的问题:多态性权限

  • 多态

多态性是对象采取多种形式的能力。对于Django模型,可以采用许多策略来完成:OneToOneField-如您所言-多表继承抽象模型代理-模型

非常好的资源:这个article和有关model inheritance的Django文档

这个非常复杂的问题都涉及:同一实体的几种形式有多少相似或不同。以及哪些操作特别相似或不同(数据形状,查询,权限等)

  • 权限设计:

您可以在几种模式中进行选择

  • 面向模型的权限:授予用户对Model的“添加”,“查看”,“编辑”或“删除”权限。 这是在Django中使用内置的Permission模型完成的,该模型具有ContentType的ForeignKey
  • 面向对象权限:每个Model 实例均向用户授予“添加”,“查看”,“编辑”或“删除”权限。有些软件包提供了此功能,例如django-guardian
  • 面向规则的权限:通过自定义逻辑(而非M2M表)向用户授予对Model实例的权限。 django rules软件包提供了这种架构。

答案 2 :(得分:2)

您可以从AbstractUser(完整的User model,包括is_superuser和is_staff等字段在内)创建一个Profile,然后,一旦有了Profile,用户就有机会创建其他类型的Profile(学生,教师或原则)。这些功能可能具有自己的功能。

对于实例,在您的模型中。py

class Profiles(AbstractUser):
    date_of_birth = models.DateField(max_length=128, blank=True, null=True, default=None, verbose_name=_(u'Date of birth'))
    principle = models.OneToOneField(Principles, null=True, blank=True, verbose_name=_(u'Principles'), on_delete=models.CASCADE)
    teacher = models.OneToOneField(Teachers, null=True, blank=True, verbose_name=_(u'Teachers'), on_delete=models.CASCADE)        
    student = models.OneToOneField(Students, null=True, blank=True, verbose_name=_(u'Students'), on_delete=models.CASCADE)  

    class Meta:
        db_table = 'profiles'
        verbose_name = _('Profile')
        verbose_name_plural = _('Profiles')

您可以向该模型添加类方法,例如

def is_teacher(self):
    if self.teacher:
        return True
    else:
        return False

然后,您的教师模型可能如下所示

class Teachers(models.Model):
    image = models.FileField(upload_to=UploadToPathAndRename(settings.TEACHERS_IMAGES_DIR), blank=True, null=True, verbose_name=_('Teacher logo'))
    name = models.CharField(blank=False, null=False, default=None, max_length=255, validators=[MaxLengthValidator(255)], verbose_name=_('Name'))
    street = models.CharField( max_length=128, blank=False, null=True, default=None, verbose_name=_('Street'))
    created_by = models.ForeignKey('Profiles', null=True, blank=True, on_delete=models.SET_NULL)
相关问题