前言
APIView
中的dispatch
是整個請求生命過程的核心方法,包含了請求模組,許可權驗證,異常模組和響應模組,我們先來介紹請求模組
請求模組:request物件
原始碼入口
APIView
類中dispatch
方法中的:request=self.iniialize_request(*args, **kwargs)
,原始碼如下:
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
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
)
原始碼分析
原始碼很簡單,第1句parser_context = self.get_parser_context(request)
,我們進入方法get_parser_context
檢視原始碼:
"""
Returns a dict that is passed through to Parser.parse(),
as the `parser_context` keyword argument.
"""
# Note: Additionally `request` and `encoding` will also be added
# to the context by the Request object.
return {
'view': self,
'args': getattr(self, 'args', ()),
'kwargs': getattr(self, 'kwargs', {})
}
上面的程式碼的意思是:返回一個解析的字典以便於Parser.parse()
去解析,另外還通過Request
物件新增了上下文request
和encoding
第二句返回了一個Request
物件,點選進入檢視
我們可以分析出,內部對request
做了二次封裝,_request
是一個HttpRequest
物件,並且Request
類中還有__getattr__
此方法,程式碼如下:
def __getattr__(self, attr):
"""
If an attribute does not exist on this instance, then we also attempt
to proxy it to the underlying HttpRequest object.
"""
try:
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
意思是如果這個例項上不存在一個屬性,那麼我們也會嘗試將其代理到底層HttpRequest
物件。接下來我們可以通過案例演示
案例演示
我們建立了TestView
檢視,檢視函式中列印了3個request
屬性,並且在response
上打了一個斷點,接下來通過url
訪問檢視,進入斷點如下,
我們可以清楚的看到:
- request是
drf
的Request
物件 - request下有
data
屬性,query_params
屬性,但是沒有GET
屬性
上面還有一個Protected Attributes
屬性,裡面包含了_request
屬性
我們可以看到_request
是WSGIHttpRequest
物件,所以它會有GET
屬性,所以我們檢視中列印的request.GET
實際上和request._request.GET
是一樣的,因為request
沒有GET
屬性,所以它就會訪問_request
中的GET
屬性,最後我們檢視列印結果,如下:
<QueryDict: {'a': ['1']}>
<QueryDict: {'a': ['1']}>
<QueryDict: {'a': ['1']}>
同樣的,POST
請求也是如此,我們在檢視中新增POST
的請求方式,如下:
def post(self, request, *args, **kwargs):
print(request.POST) # 相容
print(request._request.POST) # 二次封裝
print(request.data) # 擴充,相容性最強,3種請求方式都可以
return Response("drf post ok")
我們都知道提交資料一般有3種方式
- multipart/form-data
- application/x-www-form-urlencoded
- application/json
首先我們使用multipart/form-data
提交請求資料,並請求API
我們檢視pycharm
列印結果
<QueryDict: {'a': ['1']}>
<QueryDict: {'a': ['1']}>
<QueryDict: {'a': ['1']}>
可以看到multipart/form-data
這種請求方式,都能列印出來
接著我們使用application/x-www-form-urlencoded
提交請求資料,並請求API
<QueryDict: {'a': ['1']}>
<QueryDict: {'a': ['1']}>
<QueryDict: {'a': ['1']}>
可以看到application/x-www-form-urlencoded
這種請求方式,都能列印出來
最後我們使用application/json
提交請求資料,並請求API
可以看到application/json
這種請求方式,只有request.data
能列印出來
<QueryDict: {}>
<QueryDict: {}>
{'a': 1}
所以request.data
相容性最強
總結
drf
對request
進行了二次封裝,request._request
就是原生的WSGIRequest
- 原生
request
的屬性和方法都可以被drf
的request
物件直接訪問(相容) drf
請求的所有url
拼接引數均被解析到query_params
中,所有的資料包均被解析到data
中- 其中
post
請求,request.data
的相容性最強,能相容前臺傳輸的json
格式的資料