基本代碼結構
urls.py
rom django.conf.urls import url, include
from web.views.s5_parser import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'),
]
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import JSONParserclass TestView(APIView):# JSONParser:請求頭content-type為application/json# FormParser:請求頭content-type為application/x-www-form-urlencoded# MultiPartParser: 請求頭content-type為multipart/form-data# FileUploadParser:上傳文件parser_classes = [JSONParser, FormParser, MultiPartParser, FileUploadParser, ]def post(self, request, *args, **kwargs):print(request.content_type)# 獲取請求的值,并使用對應的JSONParser進行處理print(request.data)# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值print(request.POST)print(request.FILES)return Response('POST請求,響應內容')def put(self, request, *args, **kwargs):return Response('PUT請求,響應內容')
parser_classes屬性變量中的值,是各種解析器對象。前端會向后臺發送不同類型的請求,而django后臺的drf接口必須通過配置解析器才能獲取到相關請求數據。常用的解析器主要是“JSONParser”和“FormParser”這兩個解析器。
源碼分析
1.為什么使用parser_classes屬性變量,它有什么用?
?
同樣還是從APIView類的入口方法dispatch入口,在dispatch方法中,調用了initialize_request方法。這個方法在前文中已經說過,是用來封裝django原生的request請求的。由上圖知道,django原生的request請求數據被封裝到了Request對象中,在實例化該對象時,將解析數據的解析器初始化到了parsers屬性變量中。跳轉到get_parsers方法中,可以看到,同樣也是返回的是列表生成式。
再跳轉回APIView類中,可以看到屬性變量parser_classes定義的地方。同樣也可以通過settings配置文件進行全局配置。如果不需要進行全局配置,那就要在自定義的視圖類中對parser_classes屬性變量進行重新賦值,即:“parser_classes = [JSONParser, FormParser, MultiPartParser, FileUploadParser,]”。這列表元素都是解析器對象,只要這樣配置好,drf就會根據parser_classes中的解析器去解析數據。
?2.為什么從request.data中獲取數據?
看到這里,心中有了疑惑,Django Rest Framework框架是在那里觸發解析器這個功能的,在上面的源碼分析中并未調用任何一個關于解析相關功能的方法,只是做了一個讀取配置文件,封裝新的request對象的過程,所以是在我們需要讀數據的時候才會去觸發解析器這個功能,所以我們從request.data入手,我們知道,django原生的request請求,會被drf通過Request對象封裝,那么就跳轉到Request類定義中看看這個“data”的實現。在data方法的實現中可以看到前端請求的數據是通過“_load_data_and_files”方法獲取的,并且返回值是“_full_data”屬性變量。先跳轉到“_load_data_and_files”方法中:
?
在“_load_data_and_files”方法中可知,是通過調用“_parse”方法去獲取請求數據的,并且將請求數據保存在“_data”和“_files”屬性變量中。除文件相關的數據外的數據都保存在了“_data”中,而“_data”中的數據又都賦值到“_full_data”屬性變量中。又由上一張圖可知,“data”方法的返回值是“_full_data”,即:data方法獲取到的數據就是“_full_data”中的數據。
??
現在進一步分析_parse,首先第一步做的是獲取請求頭,可以看到將獲取到的請求頭保存到了“media_type”變量中。然后又通過調用“select_parser(self, self.parsers)”方法,來選擇所需要的解析器(參數“self.parsers”就是我們在自定義視圖中“parser_classes”的值)。
??
又通過,parser_classes中解析器對象中的parser方法來解析請求到的數據,即:“parsed = parser.parse(steam, media_type, self.parser_context)”。這里以“JSONParser”對象為例,由上圖可知,media_type屬性變量中保存的是該解析器所對應的請求頭,self.parser_context中,保存的是從前端請求中獲取到的請求頭。
再來到“JSONParser”類的“parse”方法中可知,再通過返回“json.load”來處理請求數據。返回的請求數據就會保存到“Request”類的“_parse”方法中的parsed變量中。而_parse方法的返回值為元組,第一個元素就是需要的數據。這些數據會在“_load_data_and_files”方法中,賦值給“Request”類的“_data”屬性方法,而_data中的數據會賦值給“_full_data”中。因此,“Request”類中“data”方法返回值是“_full_data”,這樣,就可以通過“request.data”獲取請求數據。
全局配置
REST_FRAMEWORK = {'DEFAULT_PARSER_CLASSES':['rest_framework.parsers.JSONParser''rest_framework.parsers.FormParser''rest_framework.parsers.MultiPartParser']
}
配置加入不同的解析器,就會解析不同類型的請求數據,當然是可以同時配置加入多個解析器的。同樣的,配置了全局解析器后,那么,在自定義的視圖類中,就可以不用通過“parser_classes”屬性變量進行添加解析器的。
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?