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
        )
posted @ 2019-11-19 20:14  Xu67  阅读(255)  评论(0编辑  收藏  举报