rest-framework之解析器
阿新 • • 發佈:2018-12-16
目錄
- 一 直譯器的作用
- 二 全域性使用直譯器
- 三 區域性使用直譯器
- 四 原始碼分析
一 直譯器的作用
根據請求頭 content-type 選擇對應的解析器對請求體內容進行處理。
有application/json(json格式字串),x-www-form-urlencoded,form-data(檔案)等格式。
二 全域性使用直譯器
settings.py 配置檔案中:
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES':[ 'rest_framework.parsers.JSONParser' 'rest_framework.parsers.FormParser' 'rest_framework.parsers.MultiPartParser' ] }
路由中:
urlpatterns = [
url(r'test/', TestView.as_view()),
]
檢視函式中:
from rest_framework.views import APIView from rest_framework.response import Response class TestView(APIView): def post(self, request, *args, **kwargs): print(request.content_type) # 獲取請求的值,並使用對應的JSONParser進行處理 print(request.data) # application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值 print(request.POST) print(request.FILES) return Response('POST請求,響應內容') def put(self, request, *args, **kwargs): return Response('PUT請求,響應內容')
三 區域性使用解析器
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.parsers import JSONParser,FormParser, MultiPartParser class TestView(APIView): parser_classes = [JSONParser, ] #在這裡填入可以被解析的型別, #如果全域性與區域性都設定瞭解析器,那麼以區域性的為準 def post(self, request, *args, **kwargs): print(request.content_type) # 獲取請求的值,並使用對應的JSONParser進行處理 print(request.data) # application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值 print(request.POST) print(request.FILES) return Response('POST請求,響應內容') def put(self, request, *args, **kwargs): return Response('PUT請求,響應內容')
注意:區域性和全域性都有直譯器時,以區域性設定的直譯器為準。
四 原始碼分析
#在呼叫request.data時,才進行解析,由此入手
@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data
#檢視self._load_data_and_files()方法---->self._data, self._files = self._parse()
def _parse(self):
#使用者請求頭裡content_type的值
media_type = self.content_type
#self.parsers 就是使用者配置的parser_classes = [FileUploadParser,FormParser ]
#self裡就有content_type,傳入此函式
parser = self.negotiator.select_parser(self, self.parsers)
#檢視self.negotiator.select_parser(self, self.parsers)
def select_parser(self, request, parsers):
#同過media_type和request.content_type比較,來返回解析器,然後呼叫解析器的解析方法
#每個解析器都有media_type = 'multipart/form-data'屬性
for parser in parsers:
if media_type_matches(parser.media_type, request.content_type):
return parser
return None
#最終呼叫parser的解析方法來解析parsed = parser.parse(stream, media_type, self.parser_context)
#Request例項化,parsers=self.get_parsers()
Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
#get_parsers方法,迴圈例項化出self.parser_classes中類物件
def get_parsers(self):
return [parser() for parser in self.parser_classes]
#self.parser_classes 先從類本身找,找不到去父類找即APIVIew 中的
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
#api_settings是一個物件,物件裡找DEFAULT_PARSER_CLASSES屬性,找不到,會到getattr方法
def __getattr__(self, attr):
if attr not in self.defaults:
raise AttributeError("Invalid API setting: '%s'" % attr)
try:
#呼叫self.user_settings方法,返回一個字典,字典再取attr屬性
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
#user_settings方法 ,通過反射去setting配置檔案裡找REST_FRAMEWORK屬性,找不到,返回空字典
@property
def user_settings(self):
if not hasattr(self, '_user_settings'):
self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
return self._user_settings