Django音乐制作协作应用如何实现单项目动态角色权限控制
Django音乐项目协调应用项目级动态权限实现方案
核心设计思路
我们采用项目-角色-权限三级绑定架构实现需求,完全避免全局角色权限固化的问题:
- 所有权限配置以单个项目为独立单元,同一角色名在不同项目可配置完全不同的权限集合
- 同一用户在不同项目可分配不同角色,权限随项目自动切换
- 支持项目内灵活增删角色、调整角色权限,无需修改代码即可适配所有业务场景
新增&改造模型定义
基于现有模型结构,只需新增2个权限相关模型,同时对JobPosition做少量字段扩展即可:
import uuid from django.db import models from django.conf import settings # 项目级权限项表:预设所有可用的权限选项,全局统一维护 class ProjectPermission(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) codename = models.CharField(max_length=100, unique=True, help_text="权限标识,例如:view_budget、edit_event") name = models.CharField(max_length=100, help_text="权限展示名称,例如:查看预算、编辑活动") # 项目自定义角色表:每个角色属于特定项目,权限独立配置 class ProjectRole(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) project = models.ForeignKey(JobProject, on_delete=models.CASCADE, related_name="custom_roles") name = models.CharField(max_length=50, help_text="角色名称,例如:鼓手、音响师、制片经理") permissions = models.ManyToManyField(ProjectPermission, blank=True, related_name="role_permissions") class Meta: unique_together = ('project', 'name') # 同一个项目内角色名唯一
对现有JobPosition模型新增用户、角色关联字段:
class JobPosition(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) title = models.ForeignKey(Title, on_delete=models.CASCADE) city = models.ForeignKey(City, on_delete=models.CASCADE) rate = models.CharField(max_length=20) jobproject = models.ForeignKey(JobProject, related_name='crew', on_delete=models.CASCADE, blank=True, null=True) # 新增关联字段 user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="project_positions", help_text="担任该职位的用户") role = models.ForeignKey(ProjectRole, on_delete=models.SET_NULL, null=True, blank=True, help_text="该职位对应的项目内角色")
权限校验逻辑实现
通用权限校验函数
先实现基础校验方法,所有场景的权限判断都基于该函数:
def has_project_permission(user, project, permission_codename): """校验指定用户在指定项目下是否拥有指定权限""" if not user.is_authenticated: return False # 超级管理员直接放行 if user.is_superuser: return True # 查询用户在该项目下所有职位关联的角色 user_positions = JobPosition.objects.filter(user=user, jobproject=project).select_related('role') for position in user_positions: if position.role and position.role.permissions.filter(codename=permission_codename).exists(): return True return False
后端接口权限控制
如果用DRF开发接口,自定义权限类即可:
from rest_framework.permissions import BasePermission class ProjectLevelPermission(BasePermission): def has_permission(self, request, view): # 从路由/请求参数中获取当前项目ID project_id = view.kwargs.get('project_id') or request.query_params.get('project_id') if not project_id: return False try: project = JobProject.objects.get(id=project_id) except JobProject.DoesNotExist: return False # 从视图属性获取当前接口需要的权限 required_perm = getattr(view, 'required_permission', None) if not required_perm: return False return has_project_permission(request.user, project, required_perm)
接口使用示例,比如预算查询接口要求view_budget权限:
class BudgetViewSet(viewsets.ReadOnlyModelViewSet): queryset = dept_budget.objects.all() permission_classes = [ProjectLevelPermission] required_permission = 'view_budget' # 指定当前接口需要的权限
前端/模板展示控制
自定义模板标签实现页面元素的权限可见性控制:
from django import template register = template.Library() @register.simple_tag def user_has_perm(user, project, perm_codename): return has_project_permission(user, project, perm_codename)
模板内使用示例:
{% load custom_tags %} {% user_has_perm request.user current_project 'view_budget' as can_view_budget %} {% if can_view_budget %} <!-- 仅有权限的用户可见预算模块 --> <div class="budget-section">{{ dept_budget.budget }}</div> {% endif %} <!-- 所有项目成员都能看到的活动信息,只要给所有角色配置view_event权限即可 --> <div class="event-info">下一场录制地点:{{ next_event.location }}</div>
权限配置管理实现
实现对应的管理页面/接口即可满足灵活配置需求:
- 项目创建后可在项目设置内新增/删除自定义角色,调整角色关联的权限
- 给职位分配用户时,选择该项目下的对应角色,用户自动继承角色的所有权限
- 如有单个用户临时权限的需求,可给
JobPosition新增extra_permissions多对多字段关联ProjectPermission,校验时叠加该字段的权限即可
业务场景适配示例
完全匹配你提出的需求场景:
- 给制片经理角色配置
view_budget、view_event权限,可查看预算和活动信息 - 给默认鼓手角色配置
view_event权限,不配置view_budget,只能看活动信息 - 若某项目需要给鼓手开放预算权限,直接在该项目的鼓手角色上新增
view_budget权限即可,不会影响其他项目的鼓手权限
内容的提问来源于stack exchange,提问作者giaggi
相关产品推荐
相关产品推荐

