能否针对单个视图实现分组动态权限管理?适配Django各类视图
Django 扩展分组权限至所有视图(含REST/MVC)
1. 自定义视图级权限模型
Django默认权限基于模型,我们需要创建自定义模型来存储视图与HTTP方法的权限关联:
# models.py from django.db import models from django.contrib.auth.models import Group class ViewPermission(models.Model): VIEW_METHODS = [ ('GET', 'GET'), ('POST', 'POST'), ('PUT', 'PUT'), ('DELETE', 'DELETE'), ('PATCH', 'PATCH'), ] view_name = models.CharField(max_length=255, unique=True, verbose_name="视图名称") http_method = models.CharField(max_length=10, choices=VIEW_METHODS, verbose_name="HTTP方法") groups = models.ManyToManyField(Group, related_name='view_permissions', verbose_name="关联分组") class Meta: unique_together = ('view_name', 'http_method') verbose_name = "视图权限" verbose_name_plural = "视图权限" def __str__(self): return f"{self.view_name} - {self.http_method}"
在admin.py注册该模型,方便后台管理:
# admin.py from django.contrib import admin from .models import ViewPermission class ViewPermissionAdmin(admin.ModelAdmin): list_display = ('view_name', 'http_method', 'get_groups') filter_horizontal = ('groups',) def get_groups(self, obj): return ", ".join([group.name for group in obj.groups.all()]) get_groups.short_description = "关联分组" admin.site.register(ViewPermission, ViewPermissionAdmin)
2. 实现权限验证逻辑
函数视图装饰器(适用于MVC函数视图)
# decorators.py from django.http import HttpResponseForbidden from .models import ViewPermission def view_permission_required(view_name): def decorator(view_func): def wrapper(request, *args, **kwargs): method = request.method.upper() # 检查当前用户所属分组是否拥有该视图的对应方法权限 has_perm = ViewPermission.objects.filter( view_name=view_name, http_method=method, groups__in=request.user.groups.all() ).exists() if not has_perm and not request.user.is_superuser: return HttpResponseForbidden("无访问权限") return view_func(request, *args, **kwargs) return wrapper return decorator
类视图Mixin(适用于MVC类视图和DRF视图)
# mixins.py from django.http import HttpResponseForbidden from rest_framework import permissions from .models import ViewPermission class ViewPermissionMixin: view_name = None # 需在子类中指定视图名称 def has_permission(self, request, *args, **kwargs): if request.user.is_superuser: return True method = request.method.upper() return ViewPermission.objects.filter( view_name=self.view_name, http_method=method, groups__in=request.user.groups.all() ).exists() # 适配Django类视图 def dispatch(self, request, *args, **kwargs): if not self.has_permission(request): return HttpResponseForbidden("无访问权限") return super().dispatch(request, *args, **kwargs) # DRF专用Mixin(可选,继承DRF的BasePermission) class DRFViewPermission(permissions.BasePermission): view_name = None def has_permission(self, request, view): if request.user.is_superuser: return True method = request.method.upper() return ViewPermission.objects.filter( view_name=self.view_name, http_method=method, groups__in=request.user.groups.all() ).exists()
3. 后台配置分组权限
运行makemigrations和migrate创建表后,进入Django后台:
- 找到「视图权限」模块,添加两条权限:
- 视图名称:
Article,HTTP方法:GET,关联分组:Author、Reader - 视图名称:
Article,HTTP方法:POST,关联分组:Author
- 视图名称:
- 后续可随时在后台给任意分组添加/移除任意视图的任意方法权限
4. 在视图中应用权限
MVC函数视图
# views.py from django.shortcuts import render from .decorators import view_permission_required @view_permission_required(view_name="Article") def article_view(request): if request.method == 'GET': # 处理GET请求逻辑 return render(request, 'article/list.html') elif request.method == 'POST': # 处理POST请求逻辑 return render(request, 'article/success.html')
MVC类视图
# views.py from django.views import View from .mixins import ViewPermissionMixin class ArticleView(ViewPermissionMixin, View): view_name = "Article" def get(self, request): # 处理GET逻辑 pass def post(self, request): # 处理POST逻辑 pass
DRF视图
# views.py from rest_framework.views import APIView from rest_framework.response import Response from .mixins import DRFViewPermission class ArticleAPIView(APIView): permission_classes = [DRFViewPermission] view_name = "Article" def get(self, request): return Response({"message": "GET请求允许"}) def post(self, request): return Response({"message": "POST请求允许"})
内容的提问来源于stack exchange,提问作者Shukurullo Makhammadjanov
相关产品推荐
相关产品推荐

