rest_framework解析器組件源碼流程

rest_framework解析器組件源碼流程

解析器顧名思義就是對請求體進行解析。爲何要有解析器?緣由很簡單,當後臺和前端進行交互的時候數據類型不必定都是表單數據或者json,固然也有其餘類型的數據格式,好比xml,因此須要解析這類數據格式就須要用到解析器(也能夠將請求體拿到,而後利用其餘模塊進行解析)。前端

rest_framework解析器就是對你請求體中的數據進行反序列化、封裝 把你的全部的請求數據都封裝在request.data中 之後就在request.data中獲取數據json

源碼分析

在APIView的dispatch方法中從新封裝了requestapi

request = self.initialize_request(request, *args, **kwargs)

執行initialize_request()方法,在該方法中,get_parsers用於獲取解析器,並被封裝到request.parsers中。

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(), #獲取全部的解析器,封裝到request.parsers中
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context

進入get_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就是當前執行APIview的類


進入parser_classes源碼
class APIView(View):

    # The following policies may be set at either globally, or per-view.
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES  #解析器全局配置
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
    metadata_class = api_settings.DEFAULT_METADATA_CLASS
    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

進入api_settings源碼

api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)#  api_settings是APISettings類實例化的對象

進入APISettings源碼

尋找parser_classes,在api_settings中找不到DEFAULT_PARSER_CLASSES,因此在APISettings中找,仍是找不到,因此運行__getattr__方法。
__getattr__函數的做用: 若是屬性查找(attribute lookup)在實例以及對應的類中(經過__dict__)失敗, 那麼會調用到類的__getattr__函數, 若是沒有定義這個函數,那麼拋出AttributeError異常。
@property
    def user_settings(self):
        if not hasattr(self, '_user_settings'):
            self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
        return self._user_settings

    def __getattr__(self, attr):  #找不到DEFAULT_PARSER_CLASSES,因此運行__getattr__函數 if attr not in self.defaults:
            raise AttributeError("Invalid API setting: '%s'" % attr)

        try:
            # Check if present in user settings
            val = self.user_settings[attr]
        except KeyError:
            # Fall back to defaults
            val = self.defaults[attr]

        # Coerce import strings into classes
        if attr in self.import_strings:    #這個函數就是首先將要導入的路徑名分割成模塊名和類名,而後再來從模塊中得到到類這個屬性,而後就完成了
            val = perform_import(val, attr)

        # Cache the result
        self._cached_attrs.add(attr)
        setattr(self, attr, val)
        return val

 




進入DEFAULTS源碼

DEFAULTS是rest_framework的默認settings配置文件,是個大字典,其中就有解析請求頭的解析器
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
),

當調用request.data獲取請求數據時候將使用解析器,下面是request.data源碼:
@property
    def data(self):
        if not _hasattr(self, '_full_data'):
            self._load_data_and_files()   #執行_load_data_and_files(),獲取請求體數據獲取文件數據
        return self._full_data
 
進入_load_data_and_files()源碼
def _load_data_and_files(self):
        """
        Parses the request content into `self.data`.
        """
        if not _hasattr(self, '_data'):
            self._data, self._files = self._parse()  #執行self_parse(),獲取解析器,並對content_type進行解析,選擇解析器,返回數據
            if self._files:                #判斷文件流數據,存在則加入到self._full_data(也就是咱們的request.data)中
                self._full_data = self._data.copy()    ,
                self._full_data.update(self._files)
            else:
                self._full_data = self._data           #不存在將無文件流的解析完成的數據賦值到self._full_data(request.data)

            # if a form media type, copy data & files refs to the underlying
            # http request so that closable objects are handled appropriately.
            if is_form_media_type(self.content_type):
                self._request._post = self.POST
                self._request._files = self.FILES
進入self._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  #獲取請求頭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)  #選擇解析器 if not parser:
            raise exceptions.UnsupportedMediaType(media_type)

        try:
            parsed = parser.parse(stream, media_type, self.parser_context)  #執行解析器的parse方法 except Exception:
            # If we get an exception during parsing, fill in empty data and
            # re-raise.  Ensures we don't simply repeat the error when
            # attempting to render the browsable renderer response, or when
            # logging the request or similar.
            self._data = QueryDict('', encoding=self._request._encoding)
            self._files = MultiValueDict()
            self._full_data = self._data
            raise

        # Parser classes may return the raw data, or a
        # DataAndFiles object.  Unpack the result as required.
        try:
            return (parsed.data, parsed.files)
        except AttributeError:
            empty_files = MultiValueDict()
            return (parsed, empty_files)
相關文章
相關標籤/搜索