• 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>
    
  • 相关阅读:
    软件工程个人作业(4)
    软件工程个人作业(3)
    软件工程个人作业(2)
    软件工程个人作业(1)
    构建之法
    消息分发机制,实现战场与UI通信功能
    设置父物体方法(包括层级)
    NGUI通过点击按钮来移动面板位置,实现翻页功能
    unity中调用android的剪切板
    屏蔽UI事件
  • 原文地址:https://www.cnblogs.com/suwanbin/p/12019289.html
Copyright © 2020-2023  润新知