You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 03:09:02