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

 

posted @ 2018-07-12 21:04  FRESHMANS  阅读(138)  评论(0)    收藏  举报