Django REST framework--渲染器

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

Django REST framework--渲染器

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函数中有 dataaccepted_media_typerenderer_context其中accepted_media_typerenderer_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)
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: go