Django Response 知多少?

390 阅读4分钟

Django Response 知多少?

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

序言

Django 是一个可以让人快速开发的框架,今天就来浅聊一下Django 接口返回的response。

大概分为几个点去进行:

  1. HttpResponse
  2. JsonResponse
  3. drf Response
  4. 自定义 drf Response

1. HttpResponse

django render 数据,返回template的时候,其实底层里面调用的就是HttpResponse。

HttpResponse 通过自身定义的函数可以看出,它返回的response其实是string类型,然后传递的content是一个bytestring。

image.png 也就是如果定义返回的数据是json类型,那么在使用HttpResponse的时候,需要用json.dumps()去对数据进行转换。

然后在前端还需要对这数据进行解析,不然得到的数据其实是一个string类型。

其实,一般来说,对于接口的开发,这种需要前后端都对数据进行转换的,其实对于开发来说都是不怎么友好的,所以就有了JsonResponse.

使用验证

    import json
    from django.http import HttpRequest, JsonResponse, HttpResponse
    
    def render_view(request: HttpRequest) -> HttpResponse:
        return HttpResponse(content=json.dumps(dict(A=1, B=2)))

结果图:

A9BE7139-185D-4893-86AF-FB61D42B6087.png

2. JsonResponse

JsonResponse是继承于HttpResponse,然后在HttpResponse的基础上把数据序列化为JSON。

它默认传递的数据得是字典类型的,如果不是会抛异常。

image.png 使用JsonResponse对于返回到前端的数据就是JSON类型,不需要前端开发同学对数据进行处理,这样子会比HttpResponse更利于开发。

但是这也有个不怎么爽快的点,就是在safe=True的时候,传递的数据必须是JSON类型,不然就报错。

对于实际开发来说,数据放回的格式其实有时候不一定是JSON,这样其实对类型限制也会部分限制了开发。

使用验证

    from django.http import HttpRequest, JsonResponse, HttpResponse

    def json_view(request: HttpRequest) -> JsonResponse:   
        return JsonResponse(data=dict(A=1, B=2))

结果图:

3E9504CB-6290-45dc-939F-3422937FDEE0.png

3. drf Response

一般来说,django经常会和drf搭配使用,当然这就不得不提起drf中的Response.

它比起JsonResponse,并没有限制死数据的类型,也就是返回的数据可以是JSON,可以是字符串,可以是列表等等。

image.png

相对于JsonResponse,这个是很不错的点。

并且数据返回到前端的类型是和后端接口提供的类型一致的,并不会说返回到前端就变成字符串。

使用验证

from rest_framework.response import Response
from rest_framework.views import APIView

class TestView(APIView):
    """
    drf Response
    """
    def get(self, request, *args, **kwargs):
        return Response(data=dict(A=1, B=2))

结果图:

039D157B-31DB-4baf-8B16-D8805C779E87.png

4. 自定义 drf Response

其实对于接口开发来说,drf Response其实已经能满足80%的要求,但是开发接口的时候,返回的数据通常是会有类似这样子的格式
ret = {
    'msg': msg,
    'status': code,
    'data': data or {},
  }

对于每个接口返回的格式都要类似这样子话,你不可能在每个接口Response 放回数据的时候,都按照这个格式一个一个这么写。

查阅drf文档,其实drf可以支持自定义drf Response.

这意味着自己自定义一个全局的drf Response,在里面定义好相应接口返回的数据格式,然后应用里面所有使用了drf Response的接口都会按照这个格式进行转换。

也就可以不用你每个接口都这么手写相同类似的字段,减少工作量。

那到底怎么去自定义drf Response呢?整理了一下,大概分为几个小点去进行:

  1. 写一个自定义的custom_response.py 文件
  2. 配置settings.py 文件里面的REST_FRAMEWORK 的 DEFAULT_RENDERER_CLASSES 配置custom_response中定义的返回格式
  3. 其他views.py 文件就正常引用Response,返回数据即可。

写一个自定义的custom_response.py 文件

from rest_framework.renderers import JSONRenderer


class RenderResponse(JSONRenderer):
        # 重构render方法
        def render(self, data, accepted_media_type=None, renderer_context=None):
                if renderer_context:
                        code_default = 0 if renderer_context["response"].status_code == 200 else renderer_context[
                                "response"].status_code
                        # 如果返回的data为字典
                        if isinstance(data, dict):
                                # 响应信息中有message和code这两个key,则获取响应信息中的message和code,并且将原本data中的这两个key删除,放在自定义响应信息里
                                # 响应信息中没有则将msg内容改为请求成功 code改为请求的状态码
                                msg = data.pop('message', 'success')
                                code = data.pop('code', code_default)

                        # 如果不是字典则将msg内容改为请求成功 code改为请求的状态码
                        else:
                                msg = 'success'
                                code = code_default

                        # 自定义返回的格式
                        ret = {
                                'msg': msg,
                                'status': code,
                                'data': data or {},
                        }
                        # 返回JSON数据
                        return super().render(ret, accepted_media_type, renderer_context)
                else:
                        return super().render(data, accepted_media_type, renderer_context)

配置settings.py 文件里面的REST_FRAMEWORK 的 DEFAULT_RENDERER_CLASSES

REST_FRAMEWORK = {
        # 修改默认返回JSON的renderer的类
        'DEFAULT_RENDERER_CLASSES': (
                'utils.custom_response.RenderResponse',
        ),
}

其他views.py 文件就正常引用Response,返回数据即可

from rest_framework.response import Response
from rest_framework.views import APIView

class TestView(APIView):
    """
    drf Response
    """
    def get(self, request, *args, **kwargs):
        return Response(data=dict(A=1, B=2))

结果图:

1CF89196-2034-4572-9C68-99D6EBB5BE5A.png

结语

截止到这里,该讲的已经讲完了,也希望这些东西能给人一点点作用,当然,文章不是完美的,有缺漏有错的也可以提出来,我也能进一步学习。

最后,如果可以,点赞支持一波也行。