如何为DRF的PermissionDenied异常添加reason字段?
问题
目前Django REST Framework的exceptions.PermissionDenied抛出后会返回403状态码及如下JSON:
{"detail": "You don't have permission to perform this action."}
我希望扩展该异常,添加reason字段,支持类似MyException(detail="Some detail here", reason="INSUFFICIENT_TIER")的调用方式,且返回的JSON中能显示reason字段。已知该异常继承自APIException,相关代码如下:
PermissionDenied类:
class PermissionDenied(APIException): status_code = status.HTTP_403_FORBIDDEN default_detail = _('You do not have permission to perform this action.') default_code = 'permission_denied'
父类APIException:
class APIException(Exception): """ Base class for REST framework exceptions. Subclasses should provide `.status_code` and `.default_detail` properties. """ status_code = status.HTTP_500_INTERNAL_SERVER_ERROR default_detail = _('A server error occurred.') default_code = 'error' def __init__(self, detail=None, code=None): if detail is None: detail = self.default_detail if code is None: code = self.default_code self.detail = _get_error_details(detail, code) def __str__(self): return str(self.detail) def get_codes(self): """ Return only the code part of the error details. Eg. {"name": ["required"]} """ return _get_codes(self.detail) def get_full_details(self): """ Return both the message & code parts of the error details. Eg. {"name": [{"message": "This field is required.", "code": "required"}]} """ return _get_full_details(self.detail)
解决方案
方法一:自定义异常类(推荐)
直接继承PermissionDenied,重写__init__方法以支持reason参数,并将其整合到返回的detail结构中:
from rest_framework import exceptions, status class CustomPermissionDenied(exceptions.PermissionDenied): def __init__(self, detail=None, code=None, reason=None): # 先调用父类初始化逻辑,处理detail和code super().__init__(detail, code) # 如果传入了reason参数,将其添加到detail字典中 if reason is not None: # 若父类处理后的detail是字符串,先转为字典格式 if isinstance(self.detail, str): self.detail = {"detail": self.detail} # 添加reason字段 self.detail["reason"] = reason
使用方式
在需要抛出权限异常的地方直接调用:
raise CustomPermissionDenied( detail="当前套餐无法访问该功能", reason="INSUFFICIENT_TIER" )
返回结果
此时接口会返回403状态码及如下JSON:
{"detail": "当前套餐无法访问该功能", "reason": "INSUFFICIENT_TIER"}
原理说明
DRF默认的异常处理器会将异常对象的detail属性直接序列化为JSON响应。通过在自定义异常中调整self.detail的结构,就能轻松添加额外字段,无需修改DRF核心代码或全局异常处理逻辑。
内容的提问来源于stack exchange,提问作者aroooo
相关产品推荐
相关产品推荐

