1.解析器概述
将前端传入的数据,根据请求头,匹配相应的解析器JSONParser
、FormParser
、MultiPartParser
、FileUploadParser
,数据解析完成后赋值给request.data
;
2.解析器应用
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser, FileUploadParser
from rest_framework.negotiation import DefaultContentNegotiation
class HomeView(APIView):
# 所有的解析器
# parser_classes = [JSONParser, FormParser]
# 根据请求,匹配对应的解析器 ; 寻找渲染器
# content_negotiation_class = DefaultContentNegotiation
def post(self, request, *args, **kwargs):
# 当调用request.data时就会触发解析的动作。
print(request.data) # {}
print(request.data) # QueryDict
return Response("OK")
3.源码分析
class Request:
def _parse(self):
media_type = self.content_type
try:
stream = self.stream
except RawPostDataException:
if not hasattr(self._request, '_post'):
raise
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)
except Exception:
self._data = QueryDict('', encoding=self._request._encoding)
self._files = MultiValueDict()
self._full_data = self._data
raise
try:
return (parsed.data, parsed.files)
except AttributeError:
empty_files = MultiValueDict()
return (parsed, empty_files)
def _load_data_and_files(self):
if not _hasattr(self, '_data'):
self._data, self._files = self._parse()
if self._files:
self._full_data = self._data.copy()
self._full_data.update(self._files)
else:
self._full_data = self._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
@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data
class APIView(View):
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
def get_content_negotiator(self):
if not getattr(self, '_negotiator', None):
self._negotiator = self.content_negotiation_class()
return self._negotiator
def get_parsers(self):
return [parser() for parser in self.parser_classes]
def get_parser_context(self, http_request):
return {
'view': self,
'args': getattr(self, 'args', ()),
'kwargs': getattr(self, 'kwargs', {})
}
def initialize_request(self, request, *args, **kwargs):
parser_context = self.get_parser_context(request)
return Request(
request, # django中的reqeust
parsers=self.get_parsers(), # 获取所有解析器的对象
negotiator=self.get_content_negotiator(), # 根据请求匹配解析器
parser_context=parser_context # 视图对象、url参数
)
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
# 核心代码-->1
request = self.initialize_request(request, *args, **kwargs)
self.initial(request, *args, **kwargs)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
class HomeView(APIView):
# 所有的解析器
# parser_classes = [JSONParser, FormParser]
# 根据请求,匹配对应的解析器 ; 寻找渲染器
# content_negotiation_class = DefaultContentNegotiation
def get(self, request, *args, **kwargs):
print(request.version)
print(request.versioning_scheme)
# 反向生成URL: http://127.0.0.1:8000/api/v1/home/
# url = request.versioning_scheme.reverse("hh", request=request)
# print(url)
return Response("...")
def post(self, request, *args, **kwargs):
# 当调用request.data时就会触发解析的动作。
print(request.data) # {}
print(request.data) # QueryDict
return Response("OK")