【问题标题】:How to implement Django multiple user types, while one user can have different role according to the project he/she is working on?如何实现 Django 多种用户类型,而一个用户可以根据他/她正在从事的项目具有不同的角色?
【发布时间】:2021-09-11 00:49:57
【问题描述】:

我找不到我的问题的解决方案,希望 cmets/帮助解决这个问题。

我想在 Django 中开发一个多用户类型模型,类似于this video,作者使用的是 Django Proxy Models

情况

我有一个 XX 项目的列表(proj01proj02projXX、...)。 所有这些项目都有自己的特定页面,可以通过特定的 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, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).filter(type=User.Types.EDITOR)


class ReviewerManager(models.Manager):
    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **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.pyviews.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, UserPassesTestMixin, 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

【问题讨论】:

  • 这已经通过 Django 的组实现。一个组有一组成员(用户对象)和一组权限。
  • 谢谢@WillemVanOnsem,你有我可以参考的例子吗?在我的情况下,我看不出如何实现组权限。
  • 您能否提供其中一个项目使用的示例视图?
  • @LordElrond Thx,我编辑了我最初的问题。如您所见,仅允许作者进行项目更新,但我希望任何审阅者或编辑都可以更改此设置。

标签: python django django-models django-permissions


【解决方案1】:

如果您有项目作为模型。您可以向模型添加自定义权限。然后为每个项目适当地将这些权限分配给您的用户(实际上也很容易添加/删除权限)。

然后在您的视图/模板中使用 user_passes_test 或 permissions_required 来限制用户可以查看/访问/编辑的内容。

    class Project(models.Model):
       project_name = ...

    class RoleType(models.Model):
       role_name = models.CharField
       # Permission boolean flags
       can_edit = models.Boolean
       can_view = models.Boolean
       
    class ProjectRole(models.Model):
        project = models.ForeignKey('Project', ...)
        role = models.ForeignKey('RoleType', ...)
        user = models.ForeignKey('User', ...)

现在您可以根据项目或用户进行反向查找

    # To show all assigned users and their roles for a project
    foo_project = Project.objects.get(project_name='foo')
    project_roles = ProjectRole.objects.filter(project=foo_project)

您还可以通过角色及其权限布尔标志来限制您的视图和模板。

【讨论】:

  • 谢谢!我真的不知道如何测试登录用户的项目变化权限。您将在哪里记录项目相关权限的列表(例如 user1: {'proj01':'reviewer', 'proj02':'editor', 'projxx': 'roleY', ... }?
  • 是的,实际上,对于不同的项目分配权限,这种解释并不适用,这将是一个更高级别的权限系统,其中某人在所有项目中都担任编辑角色。 @Arjun 的答案几乎就在那里。如果您将 Django 的用户模型子类化,您可以添加多对一文件以获得项目权限,并使用他的答案,只需进行一些小的调整。
  • 我还更新了我的答案以反映可用的布局。
  • 更新了最后一个代码部分,使其成为可用的代码。
【解决方案2】:
  • 创建定义角色的组,例如: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 只能查看项目的内容) 等等

【讨论】:

    猜你喜欢
    • 2019-12-21
    • 2020-06-09
    • 2018-07-28
    • 2020-07-17
    • 1970-01-01
    • 2012-02-07
    • 1970-01-01
    • 2012-09-02
    • 2012-11-21
    相关资源
    最近更新 更多