专栏首页小码农漫漫积累路Django-djangorestframework-渲染模块

Django-djangorestframework-渲染模块

渲染模块

可以根据用户请求 URL 或 用户可接受的类型,筛选出合适的 渲染组件。 reponse 数据 json 与 browser 两种渲染方式 浏览器 和 Postman 请求结果渲染数据的方式不一样

# 内置渲染器
# 可以根据用户请求 URL 或 用户可接受的类型,筛选出合适的 渲染组件。
# 显示json格式:JSONRenderer
http://127.0.0.1:8000/test/?format=json
http://127.0.0.1:8000/test.json

# 默认显示格式:BrowsableAPIRenderer(可以修改它的html文件)
http://127.0.0.1:8000/test/?format=admin
http://127.0.0.1:8000/test.admin
    
# 表格方式:AdminRenderer
http://127.0.0.1:8000/test/?format=form
http://127.0.0.1:8000/test.form
        
# form表单方式:HTMLFormRenderer
http://127.0.0.1:8000/test/?format=form
http://127.0.0.1:8000/test.form

渲染模块的效果

postman 测试

浏览器渲染

未提供浏览器渲染时

源码分析

入口 dispatch 中的 self.response = self.finalize_response(request, response, *args, **kwargs)

rest_framework.views.APIView#dispatch

    def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
        # 请求模块
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        # 渲染模块 -- drf 渲染模块入口
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

rest_framework.views.APIView#finalize_response

    def finalize_response(self, request, response, *args, **kwargs):
        """
        Returns the final response object.
        """
        # Make the error obvious if a proper response is not returned
        assert isinstance(response, HttpResponseBase), (
            'Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` '
            'to be returned from the view, but received a `%s`'
            % type(response)
        )

        if isinstance(response, Response):
            if not getattr(request, 'accepted_renderer', None):
                # 获得解析类 (从这里再进入)
                neg = self.perform_content_negotiation(request, force=True)
                request.accepted_renderer, request.accepted_media_type = neg

            response.accepted_renderer = request.accepted_renderer
            response.accepted_media_type = request.accepted_media_type
            response.renderer_context = self.get_renderer_context()

        # Add new vary headers to the response instead of overwriting.
        vary_headers = self.headers.pop('Vary', None)
        if vary_headers is not None:
            patch_vary_headers(response, cc_delim_re.split(vary_headers))

        for key, value in self.headers.items():
            response[key] = value

        return response

rest_framework.views.APIView#perform_content_negotiation

    def perform_content_negotiation(self, request, force=False):
        """
        Determine which renderer and media type to use render the response.
        """
        # 后去渲染类(从这里再进入)
        renderers = self.get_renderers()
        # 得到的就是渲染类的对象
        
        conneg = self.get_content_negotiator()

        try:
            return conneg.select_renderer(request, renderers, self.format_kwarg)
            # 在根据 request 请求的方式再选择具体是选择哪种渲染方式,然后再调用某个方法,把数据渲染成 页面 或 json
        except Exception:
            if force:
                return (renderers[0], renderers[0].media_type)
            raise

rest_framework.views.APIView#get_renderers

    def get_renderers(self):
        """
        Instantiates and returns the list of renderers that this view can use.
        """
        # self.renderer_classes,当前类对象没有该属性,去找类,在类属性中找到了
        return [renderer() for renderer in self.renderer_classes]
        # self.renderer_classes 遍历出来是两个渲染类,类加括号会调用类的 __init__ 方法实例化

self.renderer_classes 来源

class APIView(View):
    # self.renderer_classes 取到的即是配置中的 DEFAULT_RENDERER_CLASSES
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES

E:/python3-6-4/Lib/site-packages/rest_framework/settings.py 分析 settings 源码

"""
Settings for REST framework are all namespaced in the REST_FRAMEWORK setting.
For example your project's `settings.py` file might look like this:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.TemplateHTMLRenderer',
    ],
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
    ],
}

This module provides the `api_setting` object, that is used to access
REST framework settings, checking for user settings first, then falling
back to the defaults.
"""
from django.conf import settings
from django.test.signals import setting_changed
from django.utils.module_loading import import_string

from rest_framework import ISO_8601

DEFAULTS = {
    # Base API policies
    'DEFAULT_RENDERER_CLASSES': [
        # 默认提供了这两种渲染方式
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ],
    # ...
}
    # ...

如何自定义配置使用渲染类

得知我们可以在自己的 settings 文件中这样来配置它的解析类(全局配置)

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [  # 全局配置的解析方式,所有视图类都会受这个影响
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',  # 这个是给浏览器渲染用的,没有时浏览器渲染会报错
    ],
}
  • 在 settings.py 中配置 DEFAULT_RENDERER_CLASSES 完成的是全局配置,所有接口统一处理
  • 如果只有部分接口要做特殊化处理,可以使用局部配置
# 写成类属性就可以变成局部配置了
from rest_framework.renders import JSONRenderer

class Test2(APIView):
    renderer_classes = [JSONRenderer,]  # 必须是以一个可迭代类型(for ... 遍历它了)

    def get(self, request, *args, **kwargs):
        return Response("drf get ok 2")

    def post(self, request, *args, **kwargs):
        return Response("drf post ok 2")

查找顺序:自定义视图类(局部) => APIView 视图类 => 自定义 drf 配置(全局) => drf 默认配置

自定义渲染模块

视图类

from rest_framework.renderers import  TemplateHTMLRenderer

class BookDetailView(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    def get(self,request,pk):
        book_obj = models.Book.objects.filter(pk=pk).first()
        bs = BookSerializers(book_obj,many=False)
        return Response(bs.data,template_name='aa.html')

aa.html

<!DOCTYPE html>
<html lang="en">
<head>
    
    <title>Title</title>
</head>
<body>
{{ title }}
{{ publishDate }}
</body>
</html>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • python面向对象的继承-组合-02

    管理学生与老师小案例(老师类默认有教书的方法,而学生类是不可以有的,所以不能直接让学生类继承老师类)

    suwanbin
  • python并发编程-多线程实现服务端并发-GIL全局解释器锁-验证python多线程是否有用-死锁-递归锁-信号量-Event事件-线程结合队列-03

    正确,如果解释型语言能够利用多核优势,并行地执行代码,就会出现垃圾回收机制干扰线程数据的情况,CPython中就采用了CIL全局解释器锁来解决这一问题,牺牲多核...

    suwanbin
  • python红蓝英雄大乱斗(面向对象实现)

    备注:自己写着玩儿的程序,如有bug,请别当真,这只是python面向对象方面的一个小练习;如果你很感兴趣,期待你写一个更棒的版本分享出来一起玩哦~

    suwanbin
  • Java网络03 Servlet沙拉

    Servlet开胃酒中介绍了Servlet的基本流程和设置方式。这里,我们将看一些Servlet实例。这些实例都是HTTP通信(参考HTTP协议)中的常见问题。...

    Vamei
  • python ftp 处理

    Python中默认安装的ftplib模块定义了FTP类,其中函数有限,可用来实现简单的ftp客户端,用于上传或下载文件

    py3study
  • python-应用层-网络编程-FTP

    前面描述的基于TCP/UDP协议的网络程序开发,主要是针对传输层协议的底层代码实现 在实际操作过程中,更多的情况是直接操作应用层的数据协议的网络程序开发,如文...

    大牧莫邪
  • N元分词算法

    unigram 一元分词,把句子分成一个一个的汉字 bigram 二元分词,把句子从头到尾每两个字组成一个词语 trigram 三元分词,把句子从头到尾每三...

    学到老
  • 基础积累 | 图像分割损失函数最全面、最详细总结,含代码

    论文地址:https://arxiv.org/pdf/2006.14822.pdf

    AI算法修炼营
  • python学习要点(一)

    由于列表是动态的,所以它需要存储指针,来指向对应的元素。另外,由于列表可变,所以需要额外存储已经分配的长度大小,这样才可以即使扩容。

    luozhiyun
  • 一文看尽15种语义分割损失函数(含代码解析)

    https://github.com/shruti-jadon/Semantic-Segmentation-Loss-Functions

    Amusi

扫码关注云+社区

领取腾讯云代金券