目前在在给科室网站定义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 settings
def custom_handler(err,context: dict):
# 先调用REST framework默认的异常处理方法获得标准错误响应对象
response: Response = exception_handler(err, context)
if response is None:
# 在DEBUG模式下不处理系统异常,如果处理后错误页面将变成标准格式
if settings.DEBUG:
raise err
res = {'msg': '服务器错误!','code':500,'data':err}
return Response(res, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True) #只有500这个状态码
else:
msg = response.reason_phrase
if "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"] = msg
res["code"] = response.status_code
res['data']=data
return 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_code
if 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’]中取到相关信息就行显示就足够了。