Kyl*_*397 6 python mysql database django web
我使用 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)
Run Code Online (Sandbox Code Playgroud)
方法#2:在 User 模型中添加额外的用户类型属性
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
'''
Run Code Online (Sandbox Code Playgroud)
我的想法:
在方法 #1 中,由于内置的 User 模型有两个字段,is_staff 和 is_superuser,是否可以像上面的示例一样将这些字段实现/更改为 SuperUser/Admin 表?这意味着当我创建一个 admin/superuser 时,我希望它在 Admin 表中添加一个新行,而不是添加一个新用户并在内置 User 模型中将用户的 is_superuser 和 is_staff 字段更新为 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),
)
Run Code Online (Sandbox Code Playgroud)
但是你需要有更广泛的反思。
我认为您在谈论两个不同的问题:多态性和权限
多态性是对象具有多种形式的能力。对于 Django 模型,可以通过多种策略来完成:OneToOneField-正如您提到的- 多表继承、抽象模型或代理模型。
这个非常复杂的问题都是指:同一个实体的几种形式有多少相似或不同。以及哪些操作特别相似或不同(数据形状、查询、权限等)
您可以在多种模式中进行选择
Model。这是在 Django 中使用内置Permission模型完成的,它有一个外键ContentTypeModel 实例的“添加”、“查看”、“编辑”或“删除”权限。django-guardian例如,一些软件包提供了这种能力。rules包提供了这种架构。我在几个项目中使用的方法之一是这样的(伪代码):
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
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用此逻辑为任何操作编写包装函数,检查操作级别是否大于用户级别,例如:如果有人想要更改超级用户密码,他/她应该使用 0 级用户登录,但要更改普通用户的密码他/她应该是级别 0、1。此逻辑也可以应用于类、函数等操作。
创建基类,然后添加lvl_decorator到它然后从它固有的 => 这使您的代码超级干净并防止进一步复制粘贴。
我的意思的例子:
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:
if actor.user_lvl < action_on.action_lvl:
return True
return False
return function_wrapper
return check_lvl
class BaseClass(type):
def __new__(cls, name, bases, local):
for attr in local:
value = local[attr]
if callable(value):
local[attr] = lvl_decorator()
return type.__new__(cls, name, bases, local)
# in other locations like views.py use this sample
class FooViewDjango(object, ApiView): # don't remove object or this won't work, you can use any Django stuff you need to inherent.
__metaclass__ = BaseClass
def baz(self):
print('hora hora')
Run Code Online (Sandbox Code Playgroud)
在任何你想要的地方使用这个基类。
| 归档时间: |
|
| 查看次数: |
2756 次 |
| 最近记录: |