DRF的请求响应组件
下面我们介绍DRF的请求响应组件,主要包括三种,即请求模块,响应模块和解析模块.另外还有两个常用的相关模块,即渲染模块和异常模块.我们分别从模块的使用和源码分析来介绍,这里我们安装的DRF版本是最原始的0.1.0,所以下面的源码都是以这个版本为准的.
请求模块(request)
概念
drf的请求模块其实是在wsgi的request基础上再次封装,wsgi中的request模块是作为drf里面新的request模块的一个属性,名为_request,并对其完全兼容,且对于数据的解析鼓风机啊规范化,所有url拼接的参数都存放在了query_params
中,而所有的数据包数据都被解析并存放在了data
中,且query_params
和data
都是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来筛选出对应的渲染组件,然后将内容渲染好发给用户.
现在的主流框架所包含的内置渲染器大多包含三种
- JSONRenderer:显示json格式
- BrowsableAPIRenderer:默认显示格式
- 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
)