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

DRF自定义异常为何返回500而非202?能否重写__init__方法?

自定义API异常的问题分析与解决办法

首先给你吃个定心丸:完全可以在自定义异常类里用__init__方法,你遇到的NameError是因为类属性的初始化时机搞错了,和__init__本身没关系。

为啥会报错?

看你写的异常类代码:

class CustomExcep(APIException):
    def __init__(self, obj):
        super(CustomExcep, self).__init__()
        self.obj = obj
    status_code = 202
    default_detail = 'This already exists.{}'.format(self.obj)
    default_code = 'accepted'

这里的default_detail是类级别的属性,在Python解析这个类的定义时就会执行format(self.obj),但这时候连类的实例都还没创建,self根本不存在,自然就抛出name 'self' is not defined的错误了。

正确的写法有两种

Django REST Framework的APIException设计很灵活,我们可以用两种方式实现你的需求:

方式一:在__init__里动态设置详情信息

把detail作为实例属性来设置,避开类初始化时的时机问题:

class CustomExcep(APIException):
    # 把固定的类属性放在这里
    status_code = 202
    default_code = 'accepted'

    def __init__(self, obj):
        super().__init__()
        # 动态生成详情文本,赋值给实例的detail属性
        self.detail = f'This already exists.{obj}'

方式二:复用父类的detail参数(更简洁)

其实APIException的构造方法本身就支持传入detail参数,我们可以直接利用这个特性:

class CustomExcep(APIException):
    status_code = 202
    default_code = 'accepted'

    def __init__(self, obj):
        # 先拼接好详情文本,再传给父类的构造方法
        detail_text = f'This already exists.{obj}'
        super().__init__(detail=detail_text)

顺便提下你的序列化器方法

原代码里的duplicate_check还有个小问题:name和age变量没定义,你得从序列化器的验证数据里取,比如这样:

def duplicate_check(self):
    name = self.validated_data.get('name')
    age = self.validated_data.get('age')
    if Person.objects.filter(name=name, age=age).exists():
        raise CustomExcep('Person')
    return True

为啥移除__init__能正常跑?

当你删掉__init__直接抛CustomExcep()时,异常类会用默认的default_detail——不过你原代码里的default_detail写法本来就有问题,可能你当时临时改成了不带self的内容?总之核心是,只要分清类属性和实例属性的初始化时机,__init__完全可以正常使用。

内容的提问来源于stack exchange,提问作者david

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:53:30