1. 程式人生 > >Django之解析器

Django之解析器

一、什麼是解析器?

  對請求的資料進行解析 - 請求體進行解析。 解析器在你不拿請求體資料時 不會呼叫。

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))