问题描述
我想在 Django 中开发一个多用户类型模型,沿着作者使用 Django this video 的 Proxy Models 路线。
情况
我有一个 XX 项目列表(proj01
、proj02
、projXX
、...)。
所有这些项目都有其特定的页面,可以通过特定的 url mysite/projXX/
我有多个用户:Adam、Bob、Caroline、Dany、Ed...
每个用户可以根据他们所从事的项目拥有多个角色(例如经理、开发人员、纪录片制作人、审阅者、编辑等)
用户可以根据项目拥有不同的角色。例如。 Adam 可以是 proj01 的审稿人,但可以是 proj02 的编辑,而 Bob 可以是 proj01 的编辑,但可以是 proj02 的审稿人,等等。
我开始在下面的 models.py
文件中定义多种用户类型(仅限审阅者和编辑者角色):
# accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
class User(AbstractUser):
class Types(models.TextChoices):
EDITOR= "EDITOR","Editor"
REVIEWER = "REVIEWER","Reviewer"
base_type = Types.EDITOR
type = models.CharField(
_("Type"),max_length=50,choices=Types.choices,default=base_type
)
name = models.CharField(_("Name of User"),blank=True,max_length=255)
def get_absolute_url(self):
return reverse("users:detail",kwargs={"username": self.username})
def save(self,*args,**kwargs):
if not self.id:
self.type = self.base_type
return super().save(*args,**kwargs)
class EditorManager(models.Manager):
def get_queryset(self,**kwargs):
return super().get_queryset(*args,**kwargs).filter(type=User.Types.EDITOR)
class ReviewerManager(models.Manager):
def get_queryset(self,**kwargs).filter(type=User.Types.REVIEWER)
class EditorMore(models.Model):
user = models.OnetoOneField(User,on_delete=models.CASCADE)
gadgets = models.TextField()
class Editor(User):
base_type = User.Types.EDITOR
objects = EditorManager()
class Meta:
proxy = True
def edit(self):
return "Edition in progress"
class ReviewerMore(models.Model):
user = models.OnetoOneField(User,on_delete=models.CASCADE)
model = models.CharField(max_length=255)
make = models.CharField(max_length=255)
year = models.IntegerField()
class Reviewer(User):
base_type = User.Types.REVIEWER
objects = ReviewerManager()
@property
def more(self):
return self.reviewermore
class Meta:
proxy = True
def review(self):
return "In Review"
问题:
处理用户角色可以根据他/她正在访问的项目页面改变这一事实的最佳方法是什么?
示例:如果 Adam 已登录并访问页面 mysite/proj01/
,我希望他只能访问评论者允许的内容,而如果 Adam 访问 mysite/proj02/
,我希望用户只能看到允许编辑的内容。
理想情况下,我希望每个用户在用户数据库中都有其唯一的条目。我在想依赖于项目的角色级别可以存储为字典吗?例如:
{'proj01':'reviewer','proj02':'editor','projxx': 'roleY',... }
如何结合这个用户模型和项目相关权限列表?
编辑 02/07/21
为 project
应用、models.py
和 views.py
添加示例文件:
# projects/models.py
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
from django.urls import reverse
class Project(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
date = models.DateTimeField(auto_Now_add=True)
author = models.ForeignKey(
get_user_model(),on_delete=models.CASCADE,)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("project_detail",args=[str(self.id)])
# projects/views.py
from django.contrib.auth.mixins import (
LoginrequiredMixin,UserPassesTestMixin,)
from django.views.generic import ListView,DetailView
from django.views.generic.edit import UpdateView,DeleteView,CreateView
from django.urls import reverse_lazy
from .models import Project
class ProjectListView(LoginrequiredMixin,ListView):
model = Project
template_name = "project_list.html"
class ProjectDetailView(LoginrequiredMixin,DetailView):
model = Article
template_name = "project_detail.html"
class ProjectUpdateView(LoginrequiredMixin,UpdateView):
model = Project
fields = (
"title","body",)
template_name = "project_edit.html"
def test_func(self):
obj = self.get_object()
return obj.author == self.request.user
解决方法
您可以参考以下示例。
模型
class Project(models.Model):
title = models.CharField(max_length=255)
......
class ProjectPermission(model.Model):
project = models.ForeignKey(Project,on_delete=models.CASCADE,related_name='permissions')
role = models.ForeignKey('Role',on_delete=models.CASCADE)
can_add = models.BooleanField(default=False)
can_review = models.BooleanField(default=False)
.......
class Role(models.Model):
name = models.CharField(max_length=50) # example Moderator etc.
project_permissions = models.ManyToManyField(ProjectPermission)
users = models.ManyToManyField(User)
观看次数
#Let's create a Project instance
proj = Project.objects.create(title="Some Project")
#let's create role and assign users to role:
role = Role.objects.create(name='Reviewer')
# assign users
role.users.add(user1)
现在,假设您要为 review
角色内最近创建的 proj
实例分配 Reviewer
权限:
# first create ProjectPermission
perm = ProjectPermission.objects.create(project=proj,can_review=True,role=role)
# Now add this perm into the role:
role.project_permissions.add(perm)
现在终于可以查看用户权限了。
def review_project(request,project_id):
project = Project.objects.get(id=project_id)
if project.permissions.filter(can_review=True,role__users=request.user).exists():
# your code
else:
raise PermissionDenied
,
如果您有项目作为模型。您可以向模型添加自定义权限。然后为每个项目将这些权限适当地分配给您的用户(实际上也可以轻松添加/删除权限)。
然后在您的视图/模板中使用 user_passes_test 或 permissions_required 来限制用户可以查看/访问/编辑的内容。
class Project(models.Model):
# ...
class Meta:
permissions = (
("is_reviewer","Can review"),("is_editor","Can edit"),("is_manager","Can manage"),)
,
- 创建定义您的角色的组,例如:Group1: Editor、Group2:Manager 等
- 将每个用户分配到指定的组(您可以在 python manage.py shell 或管理面板中进行)
- 对视图添加限制,例如:/mysite/projx/ 视图仅限于 groupA,您可以查看以下问题对您有帮助:https://stackoverflow.com/a/4789038/13508969
例如: GroupA : GlobalEditor(Bob 可以在 projx 和 projy 中编辑,并且只能查看 projz)
GroupB : viewonly(Adam 只能查看 projs 的内容) 等等