如何通过装饰器为DRF的ModelViewSet各方法配置不同权限
给Django REST Framework ModelViewSet方法用装饰器设置权限的正确方式
嘿,我懂你想通过装饰器给ModelViewSet的不同方法单独配置权限的需求,咱们来拆解这个问题:
首先得说清楚:你之前直接用@permission_classes()装饰ViewSet方法的写法为什么没用——DRF的@permission_classes装饰器是为视图类设计的,不是为单个方法准备的。ViewSet的方法最终会被映射成「动作(action)」,DRF的权限检查流程默认只会读取类级别的permission_classes属性,不会去识别方法上的装饰器配置。哪怕你用了@method_decorator,也没法让DRF的权限系统正确读取到方法上的权限设置。
那如果一定要用装饰器实现这个需求,我们可以自己写一个自定义装饰器,临时替换当前方法执行时的权限配置,执行完再恢复。具体代码如下:
步骤1:自定义方法级权限装饰器
def method_permission_classes(permission_classes): def decorator(func): def wrapped_func(self, *args, **kwargs): # 保存原有的权限类配置 original_perms = self.permission_classes # 临时替换为当前方法需要的权限类 self.permission_classes = permission_classes # 重新生成权限实例(因为get_permissions会缓存实例) self.permissions = self.get_permissions() try: # 执行原方法逻辑 return func(self, *args, **kwargs) finally: # 执行完毕后恢复原来的权限配置 self.permission_classes = original_perms self.permissions = self.get_permissions() return wrapped_func return decorator
步骤2:在ViewSet方法上使用装饰器
from rest_framework import viewsets from rest_framework.permissions import IsAuthenticated from your_app.permissions import CustomPermission class abcd(viewsets.ModelViewSet): @method_permission_classes([IsAuthenticated]) def list(self, request, format=None): try: # 你的list方法逻辑 pass except Exception as e: # 异常处理 pass @method_permission_classes([CustomPermission]) def create(self, request, format=None): try: # 你的create方法逻辑 pass except Exception as e: # 异常处理 pass
补充说明
这个自定义装饰器的原理是:在方法执行前临时修改当前视图实例的permission_classes属性,重新生成权限实例;方法执行完成后再恢复原配置,避免影响其他方法的权限检查。
不过要提一句:DRF官方更推荐的还是你已经知道的get_permissions()重写方式,因为这种写法更符合DRF的设计逻辑,代码可读性也更高,不需要额外维护自定义装饰器。比如:
def get_permissions(self): if self.action == 'create': return [CustomPermission()] elif self.action == 'list': return [IsAuthenticated()] return super().get_permissions()
内容的提问来源于stack exchange,提问作者Ab1gor
相关产品推荐
相关产品推荐

