Django之解析器
阿新 • • 發佈:2018-12-05
一、什麼是解析器?
對請求的資料進行解析 - 請求體進行解析。 解析器在你不拿請求體資料時 不會呼叫。
class UsersView(APIView): def get(self,request,*args,**kwargs): return Response('...') def post(self,request,*args,**kwargs): # # application/json # print(request._request.body) # b"xxxxx" decode() json.loads# print(request._request.POST) # 無 # 當post 請求的資料格式是application/json的時候, request._request.body有值,而request._request.POST並沒有值 # 我們要通過 decode + json.loads 來獲取資料 # # www-form-url-encode # print(request._request.body) # print(request._request.POST) #當post 請求的資料格式是www-form-url-encode的時候,request._request.body和request._request.POST都有值 # 而在我們用rest framework時往往傳送的都是json格式的資料,那我們每次都要這麼費事的轉化嗎,答案肯定不是 # 可以設定 parser_classes from rest_framework.parsers import JSONParser,FormParser class UsersView(APIView): parser_classes= [JSONParser,FormParser] #表示服務端可以解析的資料格式的種類。 #如果客戶端的Content-Type的值和 application/json 匹配:JSONParser處理資料 #如果客戶端的Content-Type的值和 application/x-www-form-urlencoded 匹配:FormParser處理資料 def get(self,request,*args,**kwargs): return Response('...') def post(self,request,*args,**kwargs): # request.data 就是 處理轉化後的資料 {'name':'xxx','age':'12'} print(request.data) print(request.FILES) print(request.POST) return Response('...') # 全域性使用: 配置檔案 一般都預設使用全域性配置 REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES':[ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', ] }
2. print(request.data) 的 原始碼
class Request(object): @property def data(self): if not _hasattr(self, '_full_data'): #呼叫_load_data_and_files方法 self._load_data_and_files() return self._full_data def _load_data_and_files(self): if not _hasattr(self, '_data'): #呼叫_parse方法 self._data, self._files = self._parse() def _parse(self): #呼叫DefaultContentNegotiation類的select_parser方法,見下面 parser = self.negotiator.select_parser(self, self.parsers) # 在封裝Request的時候self.parser = 配置的解析類的物件列表 #self.negotiator = self._default_negotiator() = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS() if not parser: #如果返回 None 說明不匹配,丟擲異常 raise exceptions.UnsupportedMediaType(media_type) try: # 匹配成功, 相應的解析類物件呼叫parse方法 parsed = parser.parse(stream, media_type, self.parser_context) class DefaultContentNegotiation(BaseContentNegotiation): def select_parser(self, request, parsers): for parser in parsers: # 判斷 解析類的物件和 請求的 content_type 是否匹配 if media_type_matches(parser.media_type, request.content_type): return parser return None 拿 JSONParser 舉例 class JSONParser(BaseParser): media_type = 'application/json' renderer_class = renderers.JSONRenderer strict = api_settings.STRICT_JSON def parse(self, stream, media_type=None, parser_context=None): try: #和我們自己處理是一個原理 # 先decode decoded_stream = codecs.getreader(encoding)(stream) parse_constant = json.strict_constant if self.strict else None # 再load return json.load(decoded_stream, parse_constant=parse_constant) except ValueError as exc: raise ParseError('JSON parse error - %s' % six.text_type(exc))