1. 程式人生 > >REST Framework組件的解析源碼

REST Framework組件的解析源碼

get ica tip 代碼 返回 Coding cti sed mat

首先我們要知道解析器的作用

  • 解析器就是對你請求體中的數據進行反序列化、封裝 把你的所有的請求數據都封裝在request.data中 以後就在request.data中獲取數據

我們先導入rest_framework的解析器

from rest_framework.parsers import JSONParser,FormParser


from rest_framework.parsers import JSONParser,FormParser

class PaserView(APIView):

    parser_classes = [JSONParser,FormParser,]
    #JSONParser:表示只能解析content-type:application/json的頭
    #FormParser:表示只能解析content-type:application/x-www-form-urlencoded的頭

    def post(self,request,*args,**kwargs):
        #獲取解析後的結果
        print(request.data)
        return HttpResponse(‘paser‘)

在settings中的配置


#全局配置
REST_FRAMEWORK = {
    #版本
    "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",   
    #解析器
    "DEFAULT_PARSER_CLASSES":["rest_framework.parsers.JSONParser","rest_framework.parsers.FormParser"]
}

先通過APIView進入源碼 因為APIView是rest_framework的源碼進入口

技術分享圖片

  • 然後進入你的dispath函數中的initialize_request

技術分享圖片

   def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
        parser_context = self.get_parser_context(request)

        return Request(
            request,  # 這個時候的request已是你原生的request然後傳遞進去
            parsers=self.get_parsers(),  #獲取你的多個解析器 get_parsers()是通過你的定義 parser_classes進行的得到的信息 然後得到的列表 賦值給parsers傳遞進去然後在內部處理
            authenticators=self.get_authenticators(), # 獲取認證
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

然後你的self.get_parsers()獲取你的代碼中的parser內容賦值給parsers

技術分享圖片

 def get_parsers(self):
        """
        Instantiates and returns the list of parsers that this view can use.
        """
        return [parser() for parser in self.parser_classes]  # 返回列表生成式   遍歷你的self.parser_classes 是對你的在settings中設置的配置進行判斷

你的self.parser_classes是從你的requet類中的get_parsers是從最開始APIView中獲取值的 然後返回一個列表進行到request對象中

技術分享圖片

然後進入你的request對象中


 def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        assert isinstance(request, HttpRequest), (
            ‘The `request` argument must be an instance of ‘
            ‘`django.http.HttpRequest`, not `{}.{}`.‘
            .format(request.__class__.__module__, request.__class__.__name__)
        )

        self._request = request     # 對你的原生了request進行 封裝
        self.parsers = parsers or ()  #如果有parsers請求體重的數據就拿到沒有就為空
        self.authenticators = authenticators or ()
        self.negotiator = negotiator or self._default_negotiator()
        self.parser_context = parser_context
        self._data = Empty
        self._files = Empty
        self._full_data = Empty
        self._content_type = Empty
        self._stream = Empty

然後執行你的這個裏面的def _parse方法

    def _parse(self): # 解析器會走這個
        """
        Parse the request content, returning a two-tuple of (data, files)  # 解析請求的內容會返回兩個一個元組內部有兩個參數

        May raise an `UnsupportedMediaType`, or `ParseError` exception.
        """
        media_type = self.content_type  # 獲取你的請求體中的數據類型
        try:
            stream = self.stream
        except RawPostDataException:
            if not hasattr(self._request, ‘_post‘):
                raise
            # If request.POST has been accessed in middleware, and a method=‘POST‘
            # request was made with ‘multipart/form-data‘, then the request stream
            # will already have been exhausted.
            if self._supports_form_parsing():
                return (self._request.POST, self._request.FILES)
            stream = None

        if stream is None or media_type is None:
            if media_type and is_form_media_type(media_type):
                empty_data = QueryDict(‘‘, encoding=self._request._encoding)
            else:
                empty_data = {}
            empty_files = MultiValueDict()
            return (empty_data, empty_files)

        parser = self.negotiator.select_parser(self, self.parsers)  # select_parser 對你拿到的parsers實例化對象 然後select_parser再根據你的實例對象進行請求方式的匹配  self.parsers是拿到你的請求值

你的_parse是對你的init中的傳遞進來deparser進行加工判斷

技術分享圖片

_parse方法中的media_type = self.content_type # 獲取你的請求體中的數據類型 也是至關重要的,然後你的self.negotiator.select_parser() 就對你的傳遞進來的值進行解析判斷

點擊進入self.negotiator.select_parser()方法中

技術分享圖片

   def select_parser(self, request, parsers):
        """
        Given a list of parsers and a media type, return the appropriate
        parser to handle the incoming request.   給定解析器列表和媒體類型,返回相應的
         解析器來處理傳入的請求。
        """
        for parser in parsers:  # 對你傳遞進來的值進行請求方式的匹配
            if media_type_matches(parser.media_type, request.content_type):
                return parser
        return None

negotiator.select_parser()是通過對象本身的media_type 請求方式對你的請求體中內容進行的解析 然後這一步才最終解析完畢


綜上就是rest_framework的源碼執行流程

  • 首先你要先從APIView中獲取進入 在Request對象中中通過get_parsers方法獲取你的setting中設置的解釋器組件 然後循環這個解析器組件得到每一個解析器

  • 然後得到的解析器給parsers通過第三path方法中的initialize_request方法內部的Request對象

  • 然後Request中的_parse方法對你傳遞進來的然後針對你的parser解析器對象和請求方式media_type 獲取你的請求方式 進行請求方式和請求解析器的匹配

  • 然後你的_parse中的select_parser方法根據 media_type和解析器對象進行匹配判斷 使用對應的解析器進行請求方式的解析

  • 所以先是循環你的解析器對象 然後 把這個對象傳遞進Request中然後Request中的_parse中再對象你的請求方式和解析器匹配 然後選擇對應的解析器對你的 請求方式進行解析

純屬個人見解 看了兩天才看懂也是夠笨的了希望對正在鉆研的你有幫助、 與君共勉!!!

REST Framework組件的解析源碼