3

Django实现统一包装接口返回值数据格式 - 程序设计实验室

 2 years ago
source link: https://www.cnblogs.com/deali/p/16094959.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Django实现统一包装接口返回值数据格式 - 程序设计实验室 - 博客园

最近实在太忙了,开始了一个新的项目,为了快速形成产品,我选择了Django来实现后端,然后又拿起了之前我封装了项目脚手架「DjangoStarter」

由于前段时间我写了不少.NetCore的后端代码,对CRUD的接口开发又有了一些新的理解,所以肯定也要把DjangoStarter改造一番,改得更加顺手~

题外话:话说我在前端终于真正用上react,不得不说 ts + react 真好用,「前端带师」的安利可真不错啊(妙啊

准确来讲是搭配DjangoRestFramework来实现的,核心代码分为两部分,一个是错误处理包装,一个是响应包装renderer

无论请求是否报错,都会被我们自定义的renderer包装。

开始上代码吧~

首先在项目里添加一个新的Python包,位置根据情况自行安排,我在DjangoStarter模板中的位置是utils/response,接下来的两个文件都会放在这个目录中

第一个是错误处理的exception.py文件代码

from typing import Dict

from rest_framework.exceptions import ValidationError
from rest_framework.views import exception_handler
from rest_framework.views import Response
from rest_framework.utils.serializer_helpers import ReturnDict
from rest_framework import status


def custom_handler(err: ValidationError, context: dict):
    # 先调用REST framework默认的异常处理方法获得标准错误响应对象
    response: Response = exception_handler(err, context)

    if response is None:
        return Response({
            'message': f'服务器错误:{err}'
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True)

    else:
        res = {'message': response.reason_phrase}
        res.update(response.data)
        return Response(res, status=response.status_code, exception=True)

然后是自定义renderer.py代码:

from rest_framework.renderers import JSONRenderer


class CustomRenderer(JSONRenderer):
    # 重构render方法
    def render(self, data, accepted_media_type=None, renderer_context=None):
        if renderer_context:
            # 响应的信息,成功和错误的都是这个
            # 成功和异常响应的信息,异常信息在前面自定义异常处理中已经处理为{'message': 'error'}这种格式

            # 如果返回的data为字典
            if isinstance(data, dict):
                # 响应信息中有message和code这两个key,则获取响应信息中的message和code,并且将原本data中的这两个key删除,放在自定义响应信息里
                # 响应信息中没有则将msg内容改为请求成功 code改为请求的状态码
                msg = data.pop('message', '请求成功')
                code = data.pop('code', renderer_context["response"].status_code)
            # 如果不是字典则将msg内容改为请求成功 code改为响应的状态码
            else:
                msg = '请求成功'
                code = renderer_context["response"].status_code

            # 自定义返回的格式
            ret = {
                'message': 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)

关键的地方都注释了,很容易看懂

包装出来每个接口的返回值就都是这个样子

{
    "message": "msg",
    "code": 200,
    "data": {
        "data1": "123"
    }
}

为了让上面的代码发挥作用,还得配置一下RestFramework

编辑settings.py文件,在REST_FRAMEWORK节点添加这两个配置,注意路径要和前面两个文件的路径一致。这里我是以DjangoStarter项目为例。

REST_FRAMEWORK = {
    # 全局配置异常模块
    'EXCEPTION_HANDLER': 'utils.response.exception.custom_handler',
    # 修改默认返回JSON的renderer的类
    'DEFAULT_RENDERER_CLASSES': ('utils.response.renderer.CustomRenderer',),
}

现在就完成了~ 就是这么简单。

(比AspNetCore包装返回值简单……)

完整代码可以在GitHub上查看:https://github.com/Deali-Axy/DjangoStarter

__EOF__


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK