解析器顧名思義就是對請求體進行解析。爲何要有解析器?緣由很簡單,當後臺和前端進行交互的時候數據類型不必定都是表單數據或者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)