• DRF的请求响应组件


    DRF的请求响应组件

    下面我们介绍DRF的请求响应组件,主要包括三种,即请求模块,响应模块和解析模块.另外还有两个常用的相关模块,即渲染模块和异常模块.我们分别从模块的使用和源码分析来介绍,这里我们安装的DRF版本是最原始的0.1.0,所以下面的源码都是以这个版本为准的.

    请求模块(request)

    概念

    drf的请求模块其实是在wsgi的request基础上再次封装,wsgi中的request模块是作为drf里面新的request模块的一个属性,名为_request,并对其完全兼容,且对于数据的解析鼓风机啊规范化,所有url拼接的参数都存放在了query_params中,而所有的数据包数据都被解析并存放在了data中,且query_paramsdata都是QueryDict类型,可以通过后缀.dict()来转化为原生的dict类型.

    drf的request从根本上来说是基于CBV的一种结构,并在其上面做了各种扩展,而CBV源码中最关键的就是as_view方法和dispatch方法,drf中同样有.

    request源码简单分析

    # /rest_framework/views.py/APIView(View)
    # 上面地址可以通过下面的导入语句,然后按住ctrl+鼠标左键点击APIView进入
    from rest_framework.views import APIView
    # 121行到144行,是as_view的源码,一方面,这个源码的父类是继承于View,也就是wsgi最原始的View,所以有些方法是直接用的View中的.
    # 我们在as_view的源码中,只需要注意两点,
    
    @classmethod
        def as_view(cls, **initkwargs):
            view = super().as_view(**initkwargs)	# 该行是直接调用的其父类,也就是wsgi的View类来实现生成一个新的view,相当于重写了as_view方法,其主体逻辑还是View里面的as_view()
            return csrf_exempt(view)	# 这里返回的是局部禁用的csrf认证的view视图函数,csrf_exempt就是可以局部禁用csrf的方法
        
        
        
    # 484到511行,是DRF重写的dispatch(),其内部还是原本View内部dispatch方法,不过另外封装了两个功能,如下
        def dispatch(self, request, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs
            request = self.initialize_request(request, *args, **kwargs) # 这里就是DRF重写dispatch中对request的第二次封装,initialize_request里面是走的Request的内部__init__方法, self._request = request
            self.request = request
            self.headers = self.default_response_headers  
            try:	# try里面的内容和原装View里面dispatch的方法完全一样,即通过__getattr__方法,先从self._request反射取属性,没取到的话再从drf的request中取
                self.initial(request, *args, **kwargs)
                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)
    
            self.response = self.finalize_response(request, response, *args, **kwargs)	# 这里是对于response的第二次封装,也就是对于响应模块的第二次封装
            return self.response	
    

    响应模块(response)

    概念

    响应模块的主要作用就是根据用户发送来的URL来筛选出对应的渲染组件,然后将内容渲染好发给用户.

    现在的主流框架所包含的内置渲染器大多包含三种

    1. JSONRenderer:显示json格式
    2. BrowsableAPIRenderer:默认显示格式
    3. HTMLFormRenderer:显示form表单格式

    Response类生成对象需要参数,以及生成的对象可以使用一些属性

    • 参数: Response(data = 响应的数据,status = 响应的网络状态码, headers = 想通过响应头再携带部分信息给前端)
    • 属性: response.data response.status_code response.status_text

    使用方法

    响应模块的使用方法常有两种,局部使用和全局使用

    局部使用

    # 应用名/views.py
    from rest_framework.renderers import JSONRenderer, HTMLFormRenderer, BrowsableAPIRenderer
    from rest_framework.views import APIView
    
    
    class BookDetailView(AIPView):
            renderer_classes = [JSONRenderer,HTMLFormRenderer, BrowsableAPIRenderer]	# 括号内即是后端允许前端的渲染格式
            def get(self,request,pk):
                return Response(bs.data)
    

    全局使用

    全局使用的话需要在settings.py里面配置选项

    # settings.py
    REST_FRAMEWORK = {
        'DEFAULT_RENDERER_CLASSES':[
            'rest_framework.renderers.JSONRenderer'
        ]
    }
    
    # 在全局配置之后就不用再view视图函数里面配置了,全局的组件都会适用这个规则
    

    response源码简单分析:

    # response的源码主要在Response类的__init__方法中
    
    # 可以从下面的Response里面点进去Response方法
    from rest_framework.response import Response
    
    # response.py,14到47行,
    class Response(SimpleTemplateResponse):
        def __init__(self, data=None, status=None,
                     template_name=None, headers=None,
                     exception=False, content_type=None):	# 这里就是对response的初始化
            super().__init__(None, status=status)	
            self.data = data		# 给当前响应赋新属性,包括data,content_type等
            self.template_name = template_name
            self.exception = exception
            self.content_type = content_type
    

    解析模块(parse)

    概念

    解析模块的主要作用就是根据前端发来的请求头(content-type)的不同选择对应的解析器对请求内容进行处理,常用的请求头有application/json,x-www-form-urlencoded,form-data等格式.

    使用方法

    全局使用

    全局使用解析器非常简单,直接在settings.py里面配置就行了

    # settings.py
    REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES':[
            'rest_framework.parsers.JSONParser',	# 允许json格式
            # 'rest_framework.parsers.FormParser',	# 允许form-urlencoded
            # 'rest_framework.parsers.MultiPartParser',	# 允许form-data格式
    ]
    }
    # 上面配置完之后就可以在全局适用解析模块
    
    # urls.py
    from django.conf.urls import url
    from api import views
    
    urlpatterns = [
        url(r'^test/', views.TestView.as_view())
    ]
    
    # views.py
    class TestView(APIView):
        def post(self, request, *args, **kwargs):
            print(request.content_type)	# 因为全局配置我们只有JSONParser,所以发送来的请求只有content_type为JSONParser时才能正确解析,request.POST里面才会有值.
            print(request.data)
            print(request.POST)
            print(request.FILES)
            return Response('POST请求,响应内容')
    
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')
    

    局部使用

    局部使用也非常简单,只需要在需要使用解析器的地方加上parser_classes=[]就行了.

    # urls.py
    from django.conf.urls import url
    from api import views
    
    urlpatterns = [
        url(r'^test/', views.TestView.as_view())
    ]
    
    # views.py
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from api import models
    from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
    
    
    class TestView(APIView):
        parser_classes = [JSONParser,FormParser,MultiPartParser]	# 这里就是局部配置的配置项,括号里有的数据格式允许解析和传送,没有的数据将会被拒绝
        def post(self, request, *args, **kwargs):
            print(request.content_type)
            print(request.data)
            print(request.POST)
            print(request.FILES)
            return Response('POST请求,响应内容')
    
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')
    

    parse源码分析

    # parse的源码存在于dispatch的initialize_request方法中
    # /rest_framework/views.py
    # 381到393行
        def initialize_request(self, request, *args, **kwargs):
            parser_context = self.get_parser_context(request)	#这里提供要解析的数据
    
            return Request(
                request,
                parsers=self.get_parsers(),		#这里提供要解析的类对象
                authenticators=self.get_authenticators(),
                negotiator=self.get_content_negotiator(),
                parser_context=parser_context
            )
    
  • 相关阅读:
    Less35、Less36【无闭合注入,mysql_real_escape_string()】
    Less34【POST方式宽字符注入】
    Less29,30,31【jsp环境搭建、WAF】
    Less28、28a【select、union、空格过滤】
    Less27、27a【select、union、空格过滤】
    Less26,26a【空格符号过滤】
    Less25,25a【and/or过滤】
    Less24【二次注入】
    Less23【报错注入】
    NFC
  • 原文地址:https://www.cnblogs.com/Xu-PR/p/11892059.html
Copyright © 2020-2023  润新知