DRF中如何统一返回格式
目前在在给科室网站定义DRF的时候,遇到这样的一个问题,就是DRF的原生返回的式样是多样的,例如在访问成功的时候会返回这样的数据{“access”:fkasjfkljgkljgklsjgksjlksjfkljslfjs},但是在序列化器错误的时候,会返回类似这样的格式{‘username’: [ErrorDetail(string=‘该字段是必填项。’, code=‘required’)], ‘password’: [ErrorDetail(string=‘该字段是必填项。’, code=‘required’)]},但是另外的接口访问的时候禁止,会出现这样的形式{‘detail’: ErrorDetail(string=‘找不到指定凭据对应的有效用户’, code=‘no_active_account’)},为了可以让前端可以方便查看相关的信息,我需要将这样不同的返回统一为{‘msg’:xxx,‘code’:200,‘data’:xxx}的式样,其中涉及到两个关键的文件,一个是自定义错误处理,另外一个是关于返回前端的数据渲染,分别是以下的两个文件:
1、customException.py:
from rest_framework.views import exception_handler
from rest_framework.views import Response
from rest_framework import status
from zzer_website2 import settingsdef custom_handler(err,context: dict):# 先调用REST framework默认的异常处理方法获得标准错误响应对象response: Response = exception_handler(err, context)if response is None:# 在DEBUG模式下不处理系统异常,如果处理后错误页面将变成标准格式if settings.DEBUG:raise errres = {'msg': '服务器错误!','code':500,'data':err}return Response(res, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True) #只有500这个状态码else:msg = response.reason_phraseif "detail" in response.data:data = response.data["detail"]else:data=[]for k,v in response.data.items():if isinstance(v,list):data.append(k+v[0])res = {}res.update(response.data)res["msg"] = msgres["code"] = response.status_coderes['data']=datareturn Response(res, status=response.status_code, exception=True)
第二个:customrender.py,如下
from rest_framework.renderers import JSONRenderer# 导入控制返回的JSON格式的类
class CustomRenderer(JSONRenderer):def render(self, data, accepted_media_type=None, renderer_context=None):if renderer_context:# 判断实例的类型,返回的数据可能是列表也可能是字典if isinstance(data, dict):# 如果是字典的话应该是返回的数据,会包含 msg, code, status 等字段,必须抽离出来msg = data.pop('msg', 'success')code = renderer_context['response'].status_codeif data.get('data',None):data=data.pop('data')# 自定义返回数据格式ret = {'msg': msg,'code': code,'data': data,}# 返回 JSON 数据return super().render(ret, accepted_media_type, renderer_context)else:return super().render(data, accepted_media_type, renderer_context)
当然,在setting也需要配置好指定相关的DRF配置,如下:
REST_FRAMEWORK = {'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema','DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination','PAGE_SIZE': 15,'DEFAULT_AUTHENTICATION_CLASSES': [# 使用rest_framework_simplejwt验证身份'rest_framework_simplejwt.authentication.JWTAuthentication','rest_framework.authentication.SessionAuthentication','rest_framework.authentication.BasicAuthentication'],'DEFAULT_RENDERER_CLASSES': ['backend.utils.CustomRender.CustomRenderer','rest_framework.renderers.BrowsableAPIRenderer',],'EXCEPTION_HANDLER': 'backend.utils.CustomException.custom_handler',
}
这样的话,就可以统一后端返回的数据,前端的话,只需要都从response[‘data’]中取到相关信息就行显示就足够了。