zoukankan      html  css  js  c++  java
  • rest_framework解析器组件源码流程

    rest_framework解析器组件源码流程

    解析器顾名思义就是对请求体进行解析。为什么要有解析器?原因很简单,当后台和前端进行交互的时候数据类型不一定都是表单数据或者json,当然也有其他类型的数据格式,比如xml,所以需要解析这类数据格式就需要用到解析器(也可以将请求体拿到,然后利用其他模块进行解析)。

    rest_framework解析器就是对你请求体中的数据进行反序列化、封装 把你的所有的请求数据都封装在request.data中 以后就在request.data中获取数据

    源码分析

    在APIView的dispatch方法中重新封装了request

    request = self.initialize_request(request, *args, **kwargs)

    执行initialize_request()方法,在该方法中,get_parsers用于获取解析器,并被封装到request.parsers中。

    def initialize_request(self, request, *args, **kwargs):
            """
            Returns the initial request object.
            """
            parser_context = self.get_parser_context(request)#
    
            return Request(
                request,
                parsers=self.get_parsers(), #获取所有的解析器,封装到request.parsers中
                authenticators=self.get_authenticators(),
                negotiator=self.get_content_negotiator(),
                parser_context=parser_context

    进入get_parsers()源码
    def get_parsers(self):
            """
            Instantiates and returns the list of parsers that this view can use.
            """
            return [parser() for parser in self.parser_classes] #列表生成式,返回解析器对象,self就是当前执行APIview的类


    进入parser_classes源码
    class APIView(View):
    
        # The following policies may be set at either globally, or per-view.
        renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
        parser_classes = api_settings.DEFAULT_PARSER_CLASSES  #解析器全局配置
        authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
        throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
        permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
        content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
        metadata_class = api_settings.DEFAULT_METADATA_CLASS
        versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

    进入api_settings源码

    api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)#  api_settings是APISettings类实例化的对象

    进入APISettings源码

    寻找parser_classes,在api_settings中找不到DEFAULT_PARSER_CLASSES,所以在APISettings中找,还是找不到,所以运行__getattr__方法。
    __getattr__函数的作用: 如果属性查找(attribute lookup)在实例以及对应的类中(通过__dict__)失败, 那么会调用到类的__getattr__函数, 如果没有定义这个函数,那么抛出AttributeError异常。
    @property
        def user_settings(self):
            if not hasattr(self, '_user_settings'):
                self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
            return self._user_settings
    
        def __getattr__(self, attr):  #找不到DEFAULT_PARSER_CLASSES,所以运行__getattr__函数
            if attr not in self.defaults:
                raise AttributeError("Invalid API setting: '%s'" % attr)
    
            try:
                # Check if present in user settings
                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



    进入DEFAULTS源码

    DEFAULTS是rest_framework的默认settings配置文件,是个大字典,其中就有解析请求头的解析器
    'DEFAULT_PARSER_CLASSES': (
    'rest_framework.parsers.JSONParser',
    'rest_framework.parsers.FormParser',
    'rest_framework.parsers.MultiPartParser'
    ),

    当调用request.data获取请求数据时候将使用解析器,下面是request.data源码:
    @property
        def data(self):
            if not _hasattr(self, '_full_data'):
                self._load_data_and_files()   #执行_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()  #执行self_parse(),获取解析器,并对content_type进行解析,选择解析器,返回数据
                if self._files:                #判断文件流数据,存在则加入到self._full_data(也就是我们的request.data)中
                    self._full_data = self._data.copy()    ,
                    self._full_data.update(self._files)
                else:
                    self._full_data = self._data           #不存在将无文件流的解析完成的数据赋值到self._full_data(request.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):
            """
            Parse the request content, returning a two-tuple of (data, files)
    
            May raise an `UnsupportedMediaType`, or `ParseError` exception.
            """
            media_type = self.content_type  #获取请求头content-type
            try:
                stream = self.stream    #获取请求体
            except RawPostDataException:
                if not hasattr(self._request, '_post'):
                    raise
                # If request.POST has been accessed in middleware, and a method='POST'
                # request was made with 'multipart/form-data', then the request stream
                # will already have been exhausted.
                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)  #执行解析器的parse方法
            except Exception:
                # If we get an exception during parsing, fill in empty data and
                # re-raise.  Ensures we don't simply repeat the error when
                # attempting to render the browsable renderer response, or when
                # logging the request or similar.
                self._data = QueryDict('', encoding=self._request._encoding)
                self._files = MultiValueDict()
                self._full_data = self._data
                raise
    
            # Parser classes may return the raw data, or a
            # DataAndFiles object.  Unpack the result as required.
            try:
                return (parsed.data, parsed.files)
            except AttributeError:
                empty_files = MultiValueDict()
                return (parsed, empty_files)



























  • 相关阅读:
    Convert.ToInt32()和int.Parse()的区别
    C# 提取字符串中的数字
    asp.net FileUpload 控件上传文件 以二进制的形式存入数据库并将图片显示出来
    angularjs如何在ng-repeat过程中控制字符串长度超过指定长度后面内容以省略号显示
    html label 标签的 for 属性
    bootstrap-paginator 分页控件的使用
    时间戳的转换
    Server.MapPath() 解析
    Angularjs 日期格式转换
    1.docker 慕课入门
  • 原文地址:https://www.cnblogs.com/Mr-Murray/p/9671982.html
Copyright © 2011-2022 走看看