DRF中get_permissions方法self.action为None未返回404错误如何解决
问题原因
DRF的ViewSet执行流程中,权限校验get_permissions()的调用时机早于路由动作解析完成的时机:
当你访问的URL前缀匹配到当前UserViewSet的注册前缀(比如示例中的/accounts/),但后缀路径不符合ViewSet预设的标准动作路径规则、也没有匹配到用@action装饰器注册的自定义动作时,DRF还未完成action解析,也没走到抛出404的逻辑,就先调用了get_permissions()做权限校验,此时self.action的值为None。你在get_permissions()中手动写的断言逻辑直接抛出了错误,截断了后续的404处理流程,因此不会返回正常的404响应。
另外你写的get_serializer_class()方法也存在同类隐患:如果self.action为None或者不在你定义的serializer_classes键中,会直接抛出KeyError异常。
修复方案
1. 调整get_permissions()的空action处理逻辑
不要直接抛断言错误,遇到self.action为None时直接抛出DRF的NotFound异常,即可返回标准的404响应:
from rest_framework.exceptions import NotFound class UserViewSet(ModelViewSet): serializer_classes = { "list": UserSerializer, "retrieve": UserSerializer, "create": UserSerializer, "update": UserUpdateSerializer, } http_method_names = ["get", "post", "put"] def get_permissions(self): if self.action is None: raise NotFound() if self.action in ["list", "retrieve"]: return [IsAuthenticated(), IsAdmin()] else: return [AllowAny()]
2. 给get_serializer_class()加兜底逻辑
避免action异常时抛出KeyError,可根据需求选择以下任意一种实现:
def get_serializer_class(self): # 方式1:不存在的action用默认序列化器兜底 return self.serializer_classes.get(self.action, UserSerializer) # 方式2:不存在的action直接返回404 # if self.action not in self.serializer_classes: # raise NotFound() # return self.serializer_classes[self.action]
内容的提问来源于stack exchange,提问作者Mojtaba Arezoomand
相关产品推荐
相关产品推荐

