Django Rest Framework(六) 之解析器及源码流程
本质就是 根据请求头下Content-Type的值进行判断使用那种解析器
源码流程
从self.dispatch入口,执行self.initialize_request 封装原生request,在Request方法下有个
parsers=self.get_parsers() #为执行解析的方法,查看源码如下
get_parsers方法
def get_parsers(self): return [parser() for parser in self.parser_classes] #返回对象的实例化,查看源码
APIView类下
parser_classes = api_settings.DEFAULT_PARSER_CLASSES #DEFAULT_PARSER_CLASSES 这里还是从配置文件里设置全局的解析的类
大体流程完毕,下面进行具体分析
DEFAULT_PARSER_CLASSES 指定了解析的类,在restframework 中已经做好了封装
from rest_framework.parsers import JSONParser,FormParser
views.py
class ParseView(APIView): def post(self,request,*args,**kwargs): print (request.data) #request.data为用户提交的数据(调用解析器获取所有用户提交的数据) return HttpResponse("sssss")
但是,只有在获取request.data内容的时候,才会执行解析器,所以,此时的入口为request.data,这里的request为经过Request封装后的request(详细看源码流程)所以 request.data = Request.data
Request.data源码 @property def data(self): if not _hasattr(self, '_full_data'): self._load_data_and_files() #查看源码 return self._full_data
_load_data_and_files
def _load_data_and_files(self): """ Parses the request content into `self.data`. """ 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
self._parse
def _parse(self): media_type = self.content_type #判断用户提交的请求头的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)
#选择解析器,这里self.parsers为自己配置文件定义的parser类对象,self里包含Content-Type parser = self.negotiator.select_parser(self, self.parsers) #查看源码,看下面 if not parser: raise exceptions.UnsupportedMediaType(media_type) try:
#最后执行parser方法 parsed = parser.parse(stream, media_type, self.parser_context) #此处的parser方法为JSONParser和 FormParser类对象下的parser方法,查看源码 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)
select_parser
class DefaultContentNegotiation(BaseContentNegotiation): settings = api_settings def select_parser(self, request, parsers): for parser in parsers: if media_type_matches(parser.media_type, request.content_type): #根据content-type选择parser并返回 return parser return None
查看JSONParser源码,parser
class JSONParser(BaseParser): """ Parses JSON-serialized data. """ media_type = 'application/json' #这里表示只能解析请求头里Content-Type 为application/json的数据,如果不是这个则会报错 renderer_class = renderers.JSONRenderer strict = api_settings.STRICT_JSON def parse(self, stream, media_type=None, parser_context=None): #这里表示解析请求体的内容转换成自己想要的格式 parser_context = parser_context or {} encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET) try: decoded_stream = codecs.getreader(encoding)(stream) parse_constant = json.strict_constant if self.strict else None return json.load(decoded_stream, parse_constant=parse_constant) except ValueError as exc: raise ParseError('JSON parse error - %s' % six.text_type(exc))
全局示例配置
settings.py
REST_FRAMEWORK = { "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", "DEFAULT_VERSION":"v1", "ALLOWED_VERSIONS":['v1','v2'], "VERSION_PARAM":'version', "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser'] }
views.py
class ParseView(APIView): def post(self,request,*args,**kwargs):
#获取用户请求
#获取用户请求体
#根据用户请求头里Content-type的值去选择使用那种解析器(JSONParser或者FormParser)
#解析器处理请求体
#获取request.data print (request.data) #起始位置在这里,因为只有获取data内容的时候才会去解析数据,如果不获取,则不会进行解析数据操作 return HttpResponse("sssss")

浙公网安备 33010602011771号