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

Django解析器

1.什麼是解析器?

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

  安裝與使用:(官方文件)

  https://www.django-rest-framework.org/ 

pip install djangorestframework
 1 from rest_framewirk.views import APIView
 2 class UsersView(APIView):
 3     def get(self,request,*args,**kwargs):
 4 
 5         return Response('
...') 6 7 def post(self,request,*args,**kwargs): 8 # # application/json 9 # print(request._request.body) # b"xxxxx" decode() json.loads 10 # print(request._request.POST) # 無 11 # 當post 請求的資料格式是application/json的時候, request._request.body有值,而request._request.POST並沒有值
12 # 我們要通過 decode + json.loads 來獲取資料 13 14 # # www-form-url-encode 15 # print(request._request.body) 16 # print(request._request.POST) 17 # 當post 請求的資料格式是www-form-url-encode的時候,request._request.body和request._request.POST都有值 18 19 20 #
而在我們用rest framework時往往傳送的都是json格式的資料,那我們每次都要這麼費事的轉化嗎,答案肯定不是 21 # 可以設定 parser_classes 22 23 from rest_framework.parsers import JSONParser,FormParser 24 class UsersView(APIView): 25 parser_classes = [JSONParser,FormParser] #表示服務端可以解析的資料格式的種類。 26 #如果客戶端的Content-Type的值和 application/json 匹配:JSONParser處理資料 27 #如果客戶端的Content-Type的值和 application/x-www-form-urlencoded 匹配:FormParser處理資料 28 29 def get(self,request,*args,**kwargs): 30 return Response('...') 31 32 def post(self,request,*args,**kwargs): 33 # request.data 就是 處理轉化後的資料 {'name':'xxx','age':'12'} 34 print(request.data) 35           print(request.FILES) 36           print(request.POST) 37          return Response('...') 38 39      # 全域性使用: 配置檔案 一般都預設使用全域性配置 40         REST_FRAMEWORK = { 41        'DEFAULT_PARSER_CLASSES':[ 42     'rest_framework.parsers.JSONParser', 43     'rest_framework.parsers.FormParser', 44         ] 45         }

2.print(request.data)的原始碼

 1 class Request(object):
 2     @property
 3     def data(self):
 4         if not _hasattr(self, '_full_data'):
 5        #呼叫_load_data_and_files方法
 6             self._load_data_and_files()
 7         return self._full_data
 8         
 9     def _load_data_and_files(self):
10         if not _hasattr(self, '_data'):
11        #呼叫_parse方法
12             self._data, self._files = self._parse()
13             
14     def _parse(self):
15      #呼叫DefaultContentNegotiation類的select_parser方法,見下面
16         parser = self.negotiator.select_parser(self, self.parsers)       # 在封裝Request的時候self.parser = 配置的解析類的物件列表
17         #self.negotiator = self._default_negotiator() = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS()
18         
19         if not parser:
20             #如果返回 None  說明不匹配,丟擲異常
21             raise exceptions.UnsupportedMediaType(media_type)
22 
23         try:
24             # 匹配成功, 相應的解析類物件呼叫parse方法
25             parsed = parser.parse(stream, media_type, self.parser_context)
26         
27 class DefaultContentNegotiation(BaseContentNegotiation):
28     def select_parser(self, request, parsers):
29         for parser in parsers:
30             # 判斷 解析類的物件和 請求的 content_type 是否匹配
31             if media_type_matches(parser.media_type, request.content_type):
32                 return parser
33         return None 
34         
35         
36 拿 JSONParser 舉例
37 class JSONParser(BaseParser):
38     
39     media_type = 'application/json'
40     renderer_class = renderers.JSONRenderer
41     strict = api_settings.STRICT_JSON
42 
43     def parse(self, stream, media_type=None, parser_context=None):
44         try:          #和我們自己處理是一個原理
45             # 先decode
46             decoded_stream = codecs.getreader(encoding)(stream)
47             parse_constant = json.strict_constant if self.strict else None
48             # 再load
49             return json.load(decoded_stream, parse_constant=parse_constant)
50         except ValueError as exc:
51             raise ParseError('JSON parse error - %s' % six.text_type(exc))