Django Rest Framework之解析器

基本代碼結構

urls.py:前端

from django.conf.urls import url, include
from web.views.s5_parser import TestView

urlpatterns = [
    url(r'test/', TestView.as_view(), name='test'),
]

 views.py:python

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import JSONParser


class 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」這兩個解析器。web

源碼分析

  • 爲何會使用parser_classes屬性變量,它有什麼用?

  

  一樣仍是從APIView類的入口方法dispatch入口,在dispatch方法中,調用了initialize_request方法。這個方法在前文中已經說過,是用來封裝django原生的request請求的。由上圖知道,django原生的request請求數據被封裝到了Request對象中,在實例化該對象時,將解析數據的解析器初始化到了parsers屬性變量中。django

  

  跳轉到get_parsers方法中,能夠看到,一樣也是返回的是列表生成式。json

  

  再跳轉回APIView類中,能夠看到屬性變量parser_classes定義的地方。一樣也能夠經過settings配置文件進行全局配置。若是不須要進行全局配置,那就要在自定義的視圖類中對parser_classes屬性變量進行從新賦值,即:「parser_classes = [JSONParser, FormParser, MultiPartParser, FileUploadParser,]」。這列表元素都是解析器對象,只要這樣配置好,drf就會根據parser_classes中的解析器去解析數據。app

  • 爲何從request.data中獲取數據?

  

  既然要分析爲何是從data中獲取數據,那麼分析的入口點固然就是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」中的數據。post

  再往下看,「content_type」屬性變量是用來保存請求頭的,因此,在基本代碼結構中看到,只有設置了某些請求頭纔會經過「request.POST」來獲取請求數據。url

  下面跳轉到「_parse」方法中:spa

  

  

      

  在「_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」屬性變量進行添加解析器的。

相關文章
相關標籤/搜索