如何修改Django PermissionRequiredMixin适配Django Guardian对象级权限校验
自定义PermissionRequiredMixin实现全局与对象级权限双重校验
实现思路
原生PermissionRequiredMixin仅校验全局权限,我们只需重写其has_permission方法,先校验全局权限,校验通过直接放行;全局权限不通过时再校验指定对象的对象级权限即可。
实现代码
from django.contrib.auth.mixins import PermissionRequiredMixin as BasePermissionRequiredMixin class PermissionRequiredMixin(BasePermissionRequiredMixin): # 如需固定校验对象可直接赋值,否则重写get_permission_object方法 permission_object = None def get_permission_object(self): """重写该方法返回需要校验权限的目标对象实例""" return self.permission_object def has_permission(self): perms = self.get_permission_required() # 优先校验全局权限,全局有权限直接放行 if self.request.user.has_perms(perms): return True # 全局权限不通过,尝试校验对象级权限 perm_obj = self.get_permission_object() if not perm_obj: return False # 逐个校验所有需要的权限是否在目标对象上授予 for perm in perms: if not self.request.user.has_perm(perm, perm_obj): return False return True
使用示例
以你的MainPageView为例,只需继承自定义的PermissionRequiredMixin,并重写get_permission_object方法返回需要校验的对象即可:
class MainPageView(PermissionRequiredMixin, TemplateView): permission_required = "app.view_mainpage" template_name = "web/mainpage.html" def get_permission_object(self): # 替换为你实际的对象获取逻辑,例如根据URL参数、当前站点信息查询等 from app.models import MainPage return MainPage.objects.get(site_id=self.request.site.id)
如果是DetailView、UpdateView这类自带对象查询逻辑的视图,可以直接复用get_object方法:
class MainPageDetailView(PermissionRequiredMixin, DetailView): permission_required = "app.view_mainpage" model = MainPage def get_permission_object(self): return self.get_object()
逻辑说明
- 属于全局权限组的用户会在第一步全局权限校验时直接通过,无需走对象级校验
- 仅持有特定对象权限的用户,全局校验失败后会自动走对象级权限校验,校验通过即可访问
- 你所有权限content_type一致的特性刚好适配该逻辑,无需额外添加类型判断代码
内容的提问来源于stack exchange,提问作者kaiser
相关产品推荐
相关产品推荐

