Django REST framework--渲染器
- Django REST framework--渲染器
- 自定义接口规范
- 渲染器基本原理
- Django 项目debug调试技巧
- 异常信息处理
- 配置异常处理模块
- 自定义异常处理
Django REST framework–渲染器
自定义接口规范
目前使用的是REST框架默认的返回格式,类似这种
[
{
"id": 38,
"method": 0,
"url": "/api/teacher/",
"params": null,
"headers": null,
"cookies": null,
"data": {
"name": "小王老师",
"courses": "英语",
"address": "广东深圳"
},
"json": null,
"step": null
},
{
"id": 39,
"method": 0,
"url": "/api/teacher/",
"params": null,
"headers": null,
"cookies": null,
"data": {
"name": "小王老师",
"courses": "英语",
"address": "广东深圳"
},
"json": null,
"step": null
}
]
没有自定义响应字段封装,不利于前端的渲染和接口验证
希望接口在正确的时候返回
{"msg":"success","retcode":200,"retlist":[...]}
接口在错误的时候返回
{"msg":"error","retcode":404,"error":error_msg}
想要弄成类似这样的效果需要自定义DRF异常返回和自定义数据返回格式,在项目根目录下新增一个文件夹utils
,在该文件夹下新建renderers.py
文件并写入以下代码
from rest_framework.renderers import JSONRenderer
# 自定义渲染器
class MyRenderer(JSONRenderer):
# 重构 render方法
def render(self,data,accepted_media_type=None,renderer_context=None):
# 响应状态码
status_code = renderer_context['response'].status_code
# 正常返回 status_code 以2开头
if str(status_code).startswith('2'):
res = {'msg':"success",'retcode':status_code,'retlist':data}
# 返回父类方法
return super().render(res,accepted_media_type,renderer_context)
# 异常情况
else:
res = {'msg':"error",'retcode':status_code}
return super().render(res,accepted_media_type,renderer_context)
在settings.py
文件底部添加DRF全局配置
# rest框架配置
REST_FRAMEWORK = {
# 默认的渲染器
'DEFAULT_RENDERER_CLASSES': (
# 'rest_framework.renderers.JSONRenderer',
# 'rest_framework.renderers.BrowsableAPIRenderer',
'utils.renderers.MyRenderer',
)
}
执行命令python manage.py runserver 0.0.0.0:8888
启动项目,在浏览器中输入http://127.0.0.1:8888/requests/38
,可以发现返回带响应字段的json数据
{
"msg": "success",
"retcode": 200,
"retlist": {
"id": 38,
"method": 0,
"url": "/api/teacher/",
"params": null,
"headers": null,
"cookies": null,
"data": {
"name": "小王老师",
"courses": "英语",
"address": "广东深圳"
},
"json": null,
"step": null
}
}
在浏览器中输入不存在的id,返回失败,http://127.0.0.1:8888/requests/38
,可以发现返回带异常字段的json数据
{"msg":"error","retcode":404}
若在浏览器中输入http://127.0.0.1:8888/requests/
,则返回数据库中查询的所有数据,器json数据内容会放到以retlist
为名的列表里
{
"msg": "success",
"retcode": 200,
"retlist": [
{
"id": 38,
"method": 0,
"url": "/api/teacher/",
"params": null,
"headers": null,
"cookies": null,
"data": {
"name": "小王老师",
"courses": "英语",
"address": "广东深圳"
},
"json": null,
"step": null
},
{
"id": 39,
"method": 0,
"url": "/api/teacher/",
"params": null,
"headers": null,
"cookies": null,
"data": {
"name": "小王老师",
"courses": "英语",
"address": "广东深圳"
},
"json": null,
"step": null
}
]
}
渲染器基本原理
序列化在返回数据后并不是直接做为响应数据,而是经过渲染器的渲染,生成不同格式的响应内容,如html或json格式。REST本身支持HTML和json格式,有内置的渲染器。那么如果想要返回定制化的内容就要重写渲染器,按照指定的格式进行响应
重构渲染器就是重写父类渲染器的render方法,在renderers.py
文件中,就是通过定义一个MyRenderer
类来自定义渲染器,然后通过自定义render
函数,来重写父类渲染器的render方法
def render(self,data,accepted_media_type=None,renderer_context=None):
自定义render
函数中有 data
、accepted_media_type
和renderer_context
,其中accepted_media_type
和renderer_context
默认为None,也就是说这两个参数是可选的。
data
指响应数据(序列化器的.data属性),等同于renderer_context[" response "].data
的值
accepted_media_type
是由内容协商阶段确定的所接受的媒体类型。根据客户端的 Accept:
头,这可能比渲染器的 media_type
属性更具体,可能包括媒体类型参数。例如 "application/json; nested=true"
。
renderer_context
是一个由view提供的上下文信息的字典。默认情况下这个字典会包括以下键: view , request , response , args , kwargs 。
-
renderer_context[" view "]
对应调用的视图函数 -
renderer_context[" request "]
对应本次请求对象,包含所有请求数据,如请求头,请求参数等等 -
renderer_context[" response "]
对应本次响应对象,包含所有响应数据,如响应头,状态码,响应数据等等
最后,通过super()
将参数内容返回父类方法。
如果响应状态码status_code
以2开头,则说明响应成功,将{'msg':"success",'retcode':status_code,'retlist':data}
作为data数据返回给父类方法;
如果响应状态码status_code
不以2开头,则说明响应失败,将{'msg':"error",'retcode':status_code}
作为data数据返回给父类方法
Django 项目debug调试技巧
点击pycharm右上角,选中Edit Configurations
,添加Django Server
,编辑运行配置内容,应用成功后,点击调试按钮进行调试
在return super().render(res,accepted_media_type,renderer_context)
这行代码打上断点,然后在浏览器中输入http://127.0.0.1:8888/requests/38
,通过pycharm查看debug控制台打印内容,了解数据的流转过程及数据内容
异常信息处理
当前情况下我们智能获取到正常情况下返回的数据,如果想返回异常信息,需要了解下REST异常处理机制,
REST默认情况可以处理的异常有:
-
在REST framework内部产生的 APIException 的子类异常。
-
原生Django的 Http404 异常.
-
原生Django的 PermissionDenied 异常.
如果想要获取异常数据,需要从异常处理器中提取,REST默认的是 exception_handler,当触发异常时,获取到异常的响应信息,便可以自由定义其格式。
配置异常处理模块
在settings.py
文件底部添加DRF全局配置
# rest框架配置
REST_FRAMEWORK = {
# 全局配置异常模块
'EXCEPTION_HANDLER': 'utils.exception.my_exception_handler',
# 默认的渲染器
'DEFAULT_RENDERER_CLASSES': (
'utils.renderers.MyRenderer',
)
}
自定义异常处理
增加异常处理
在utils
文件夹下新建exception.py
文件并写入以下代码
from rest_framework.views import exception_handler, Response
def my_exception_handler(exc, context): # exc:异常信息 context:上下文
# 首先调用REST framework默认的异常处理,以获得标准的错误响应。
error_response = exception_handler(exc, context)
if error_response:
# 成功捕获到异常的情况
error_response.data['msg'] = 'error' # 标记
error_response.data['retcode'] = error_response.status_code # 状态码
error_response.data['error'] = str(exc) # 详细错误原因
error_response.data.pop('detail') # detail的异常信息比较简单
return error_response
更新渲染器逻辑
from rest_framework.renderers import JSONRenderer
# 自定义渲染器
class MyRenderer(JSONRenderer):
# 重构 render方法
def render(self,data,accepted_media_type=None,renderer_context=None):
# 默认把data作为响应数据
resp_content = data
if renderer_context:
# 响应状态码
status_code = renderer_context['response'].status_code
# 正常返回 status_code 以2开头
if str(status_code).startswith('2'):
# 判断响应内容是否是列表形式,如果不是列表形式,则变成列表形式以对应接口要求
if not isinstance(resp_content, list):
resp_content = [resp_content]
res = {'msg':"success",'retcode':status_code,'retlist':data}
# 返回父类方法
return super().render(res,accepted_media_type,renderer_context)
# 异常情况
return super().render(resp_content,accepted_media_type,renderer_context)