自定义响应渲染器 最后更新时间:2025年07月02日 如果你采用**方法二(自定义响应渲染器)**,并且需要自定义返回的 `code` 字段(区别于 HTTP 状态码),可以通过以下方式实现: ### 方案一:在视图中设置自定义状态码 在视图方法中通过 `response.data` 添加自定义状态码,渲染器读取该值: ```python # 视图中 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 ``` 修改渲染器代码: ```python # 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) ``` ### 方案二:使用自定义异常处理 定义业务异常类,在抛出异常时携带自定义状态码: ```python # 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) ``` 修改渲染器: ```python # 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) ``` 使用示例: ```python # 在视图中抛出异常 from utils.exceptions import CustomAPIException def some_view(self, request): if not request.user.is_authenticated: raise CustomAPIException("未登录", code=4001) ``` ### 方案三:全局状态码映射配置 在 `settings.py` 中配置 HTTP 状态码与业务状态码的映射关系: ```python # settings.py CUSTOM_STATUS_CODE_MAPPING = { 200: 2000, 201: 2001, 400: 4000, 401: 4001, # ...其他映射 } ``` 渲染器读取配置: ```python # 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`: ```python 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