我使用Django已经有一段时间了,但是直到现在我还没有想到这一点。
当前,我有一个包含不同用户级别的项目。通常,根据我过去的经验,我仅使用Django开发系统,只有两个用户级别,即超级用户和普通/常规用户。所以我的问题是在模型/数据库中呈现这些不同用户级别的有效方法是什么?在这里,我将以学校系统为例,并提供一些初步的想法。实施它。
用户级别:
方法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中,问题在于具有不同访问权限的表直接连接到它。例如,薪金模型(学生用户无法访问)与用户模型(包含学生用户)具有直接链接。
我希望我能够获得一些见识,并且也能以适当有效的方式来实现此目的,以防止将来出现任何实现上的不便和错误。非常感谢。
答案 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
。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)