如果你采用方法二(自定义响应渲染器),并且需要自定义返回的 code 字段(区别于 HTTP 状态码),可以通过以下方式实现:
方案一:在视图中设置自定义状态码
在视图方法中通过 response.data 添加自定义状态码,渲染器读取该值:
# 视图中
class TimeMoudelSet(viewsets.ModelViewSet):
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
# 自定义业务状态码(非HTTP状态码)
response = Response(serializer.data)
response.data = {
"data": serializer.data,
"custom_code": 2000 # 自定义业务状态码
}
return response修改渲染器代码:
# utils/renderers.py
from rest_framework.renderers import JSONRenderer
class CustomJSONRenderer(JSONRenderer):
def render(self, data, accepted_media_type=None, renderer_context=None):
response = renderer_context['response']
http_status = response.status_code
# 默认业务状态码(与HTTP状态码映射)
business_code = {
200: 2000, # 成功
201: 2001, # 创建成功
400: 4000, # 参数错误
401: 4001, # 未认证
403: 4003, # 权限拒绝
404: 4004, # 资源不存在
500: 5000, # 服务器错误
}.get(http_status, 5000)
# 如果视图中设置了custom_code,则使用它
if isinstance(data, dict) and 'custom_code' in data:
business_code = data.pop('custom_code') # 移除自定义code,避免嵌套
# 错误处理
if isinstance(data, dict) and 'detail' in data:
return super().render({
"data": None,
"code": business_code,
"message": data['detail']
}, accepted_media_type, renderer_context)
# 成功响应
return super().render({
"data": data,
"code": business_code
}, accepted_media_type, renderer_context)方案二:使用自定义异常处理
定义业务异常类,在抛出异常时携带自定义状态码:
# utils/exceptions.py
from rest_framework.exceptions import APIException
class CustomAPIException(APIException):
status_code = 400 # HTTP状态码
default_code = 4000 # 业务状态码
def __init__(self, detail=None, code=None):
self.code = code or self.default_code
super().__init__(detail=detail)修改渲染器:
# utils/renderers.py
from rest_framework.renderers import JSONRenderer
from utils.exceptions import CustomAPIException
class CustomJSONRenderer(JSONRenderer):
def render(self, data, accepted_media_type=None, renderer_context=None):
response = renderer_context['response']
http_status = response.status_code
# 默认业务状态码
business_code = {
200: 2000,
201: 2001,
# ...其他映射
}.get(http_status, 5000)
# 如果是自定义异常,获取其业务状态码
exception = getattr(response, 'exception', False)
if exception and isinstance(getattr(response, 'data', None), dict):
# 从异常中获取业务状态码(如果有)
if hasattr(response.exception, 'code'):
business_code = response.exception.code
# 错误处理
if isinstance(data, dict) and 'detail' in data:
return super().render({
"data": None,
"code": business_code,
"message": data['detail']
}, accepted_media_type, renderer_context)
# 成功响应
return super().render({
"data": data,
"code": business_code
}, accepted_media_type, renderer_context)使用示例:
# 在视图中抛出异常
from utils.exceptions import CustomAPIException
def some_view(self, request):
if not request.user.is_authenticated:
raise CustomAPIException("未登录", code=4001)方案三:全局状态码映射配置
在 settings.py 中配置 HTTP 状态码与业务状态码的映射关系:
# settings.py
CUSTOM_STATUS_CODE_MAPPING = {
200: 2000,
201: 2001,
400: 4000,
401: 4001,
# ...其他映射
}渲染器读取配置:
# utils/renderers.py
from rest_framework.renderers import JSONRenderer
from django.conf import settings
class CustomJSONRenderer(JSONRenderer):
def render(self, data, accepted_media_type=None, renderer_context=None):
response = renderer_context['response']
http_status = response.status_code
# 从配置中获取业务状态码映射
code_mapping = getattr(settings, 'CUSTOM_STATUS_CODE_MAPPING', {})
business_code = code_mapping.get(http_status, 5000)
# ...后续代码同之前方案推荐方案(方案一)
对于你的场景,最简单的方式是在视图中直接设置 custom_code:
class TimeMoudelSet(viewsets.ModelViewSet):
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
response = Response(serializer.data)
response.data = {
"data": serializer.data,
"custom_code": 2000 # 业务成功状态码
}
return response渲染器代码保持不变,自动读取并使用 custom_code 作为返回的 code 字段。这样可以灵活控制每个接口的业务状态码。


Comments | NOTHING