rest_framework解析器组件源码流程

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

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

源码分析

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

  1. request = self.initialize_request(request, *args, **kwargs)
  2.  
  3. 执行initialize_request()方法,在该方法中,get_parsers用于获取解析器,并被封装到request.parsers中。
  1. def initialize_request(self, request, *args, **kwargs):
  2. """
  3. Returns the initial request object.
  4. """
  5. parser_context = self.get_parser_context(request)#
  6.  
  7. return Request(
  8. request,
  9. parsers=self.get_parsers(), #获取所有的解析器,封装到request.parsers中
  10. authenticators=self.get_authenticators(),
  11. negotiator=self.get_content_negotiator(),
  12. parser_context=parser_context
  1. 进入get_parsers()源码
  1. def get_parsers(self):
  2. """
  3. Instantiates and returns the list of parsers that this view can use.
  4. """
  5. return [parser() for parser in self.parser_classes] #列表生成式,返回解析器对象,self就是当前执行APIview的类
  1.  
  2. 进入parser_classes源码
  1. class APIView(View):
  2.  
  3. # The following policies may be set at either globally, or per-view.
  4. renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
  5. parser_classes = api_settings.DEFAULT_PARSER_CLASSES #解析器全局配置
  6. authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
  7. throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
  8. permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
  9. content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
  10. metadata_class = api_settings.DEFAULT_METADATA_CLASS
  11. versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
  1. 进入api_settings源码
  2.  
  3. api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)#  api_settingsAPISettings类实例化的对象
  1. 进入APISettings源码
  2.  
  3. 寻找parser_classes,在api_settings中找不到DEFAULT_PARSER_CLASSES,所以在APISettings中找,还是找不到,所以运行__getattr__方法。
    __getattr__函数的作用: 如果属性查找(attribute lookup)在实例以及对应的类中(通过__dict__)失败, 那么会调用到类的__getattr__函数, 如果没有定义这个函数,那么抛出AttributeError异常。
  1. @property
  2. def user_settings(self):
  3. if not hasattr(self, '_user_settings'):
  4. self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
  5. return self._user_settings
  6.  
  7. def __getattr__(self, attr):  #找不到DEFAULT_PARSER_CLASSES,所以运行__getattr__函数
  8. if attr not in self.defaults:
  9. raise AttributeError("Invalid API setting: '%s'" % attr)
  10.  
  11. try:
  12. # Check if present in user settings
  13. val = self.user_settings[attr]
  14. except KeyError:
  15. # Fall back to defaults
  16. val = self.defaults[attr]
  17.  
  18. # Coerce import strings into classes
  19. if attr in self.import_strings:    #这个函数就是首先将要导入的路径名分割成模块名和类名,然后再来从模块中获得到类这个属性,然后就完成了
  20. val = perform_import(val, attr)
  21.  
  22. # Cache the result
  23. self._cached_attrs.add(attr)
  24. setattr(self, attr, val)
  25. return val
  1.  
  1. 进入DEFAULTS源码
  1. DEFAULTSrest_framework的默认settings配置文件,是个大字典,其中就有解析请求头的解析器
  1. 'DEFAULT_PARSER_CLASSES': (
    'rest_framework.parsers.JSONParser',
    'rest_framework.parsers.FormParser',
    'rest_framework.parsers.MultiPartParser'
    ),
  1. 当调用request.data获取请求数据时候将使用解析器,下面是request.data源码:
    @property
  1. def data(self):
  2. if not _hasattr(self, '_full_data'):
  3. self._load_data_and_files() #执行_load_data_and_files(),获取请求体数据获取文件数据
  4. return self._full_data
  1.  
  1. 进入_load_data_and_files()源码
  1. def _load_data_and_files(self):
  2. """
  3. Parses the request content into `self.data`.
  4. """
  5. if not _hasattr(self, '_data'):
  6. self._data, self._files = self._parse() #执行self_parse(),获取解析器,并对content_type进行解析,选择解析器,返回数据
  7. if self._files:                #判断文件流数据,存在则加入到self._full_data(也就是我们的request.data)中
  8. self._full_data = self._data.copy()
  9. self._full_data.update(self._files)
  10. else:
  11. self._full_data = self._data #不存在将无文件流的解析完成的数据赋值到self._full_data(request.data)
  12.  
  13. # if a form media type, copy data & files refs to the underlying
  14. # http request so that closable objects are handled appropriately.
  15. if is_form_media_type(self.content_type):
  16. self._request._post = self.POST
  17. self._request._files = self.FILES
  1. 进入self._parse()源码
  1. def _parse(self):
  2. """
  3. Parse the request content, returning a two-tuple of (data, files)
  4.  
  5. May raise an `UnsupportedMediaType`, or `ParseError` exception.
  6. """
  7. media_type = self.content_type  #获取请求头content-type
  8. try:
  9. stream = self.stream    #获取请求体
  10. except RawPostDataException:
  11. if not hasattr(self._request, '_post'):
  12. raise
  13. # If request.POST has been accessed in middleware, and a method='POST'
  14. # request was made with 'multipart/form-data', then the request stream
  15. # will already have been exhausted.
  16. if self._supports_form_parsing():
  17. return (self._request.POST, self._request.FILES)
  18. stream = None
  19.  
  20. if stream is None or media_type is None:
  21. if media_type and is_form_media_type(media_type):
  22. empty_data = QueryDict('', encoding=self._request._encoding)
  23. else:
  24. empty_data = {}
  25. empty_files = MultiValueDict()
  26. return (empty_data, empty_files)
  27.  
  28. parser = self.negotiator.select_parser(self, self.parsers)  #选择解析器
  29.  
  30. if not parser:
  31. raise exceptions.UnsupportedMediaType(media_type)
  32.  
  33. try:
  34. parsed = parser.parse(stream, media_type, self.parser_context) #执行解析器的parse方法
  35. except Exception:
  36. # If we get an exception during parsing, fill in empty data and
  37. # re-raise. Ensures we don't simply repeat the error when
  38. # attempting to render the browsable renderer response, or when
  39. # logging the request or similar.
  40. self._data = QueryDict('', encoding=self._request._encoding)
  41. self._files = MultiValueDict()
  42. self._full_data = self._data
  43. raise
  44.  
  45. # Parser classes may return the raw data, or a
  46. # DataAndFiles object. Unpack the result as required.
  47. try:
  48. return (parsed.data, parsed.files)
  49. except AttributeError:
  50. empty_files = MultiValueDict()
  51. return (parsed, empty_files)
  1.  

rest_framework解析器组件源码流程的更多相关文章

  1. DRF-解析器组件源码解析

    解析器组件源码解析 解析器组件源码解析 1 执行request.data 开始找重装的request中的data方法 2 在dispatch找到重装的request def dispatch(self ...

  2. Django admin组件源码流程

    admin 组件 Django 自带的用户后台组件 用于用户便携的操作 admin 组件核心 启动 注册 设计url 启动核心代码 每个app 通过 apps.py 扫描 admin.py 文件 并执 ...

  3. Django的rest_framework的分页组件源码分析

    前言: 分页大家应该都很清楚,今天我来给大家做一下Django的rest_framework的分页组件的分析:我的讲解的思路是这样的,分别使用APIview的视图类和基于ModelViewSet的视图 ...

  4. DRF之解析器组件及序列化组件

    知识点复习回顾一:三元运算 三元运算能够简化我们的代码,  请看如下代码: # 定义两个变量 a = 1 b = 2 # 判断a的真假值,如果为True,则将判断表达式的前面的值赋给c,否则将判断表达 ...

  5. DRF 解析器组件

    Django无法处理application/json协议请求的数据,即,如果用户通过application/json协议发送请求数据到达Django服务器,我们通过request.POST获取到的是一 ...

  6. Rest_Framework之认证、权限、频率组件源码剖析

    一:使用RestFramwork,定义一个视图 from rest_framework.viewsets import ModelViewSet class BookView(ModelViewSet ...

  7. abp vnext2.0核心组件之领域实体组件源码解析

    接着abp vnext2.0核心组件之模块加载组件源码解析和abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析集合.Net Core3.1,基本环境已经完备, ...

  8. DjangoRestFramework 学习之restful规范 APIview 解析器组件 Postman等

    DjangoRestFramework学习一之restful规范.APIview.解析器组件.Postman等 本节目录 一 预备知识 二 restful规范 三 DRF的APIView和解析器组件 ...

  9. day89 DjangoRsetFramework学习---restful规范,解析器组件,Postman等

     DjangoRsetFramework学习---restful规范,解析器组件,Postman等           本节目录 一 预备知识 二 restful规范 三 DRF的APIView和解析 ...

随机推荐

  1. java基础-集合笔记

    Iterator(foreach) 遍历时只能通过iterator去删除(添加)元素,不能直接通过集合对象删除或添加元素 Set HashSet底层是一个HashMap HashSet添加元素,先判断 ...

  2. uva 465 - Overflow 高精度还是浮点数?

    uva 465 - Overflow  Overflow  Write a program that reads an expression consisting of two non-negativ ...

  3. 努比亚Z18mini多点对焦

    25点对焦 分为了中心对焦.中间对焦.边缘对焦三个区域 [参考文献] 手机上感受单反的“多点对焦”努比亚Z18mini给你想象 https://baijiahao.baidu.com/s?id=160 ...

  4. TaoKeeper

    基于zookeeper的监控管理工具taokeeper,由淘宝团队开源的zk管理中间件: 按照taokeeper官方说明 http://jm-blog.aliapp.com/?p=1450 下载tao ...

  5. plsql参数

    PL/SQL中对out,in out参数使用的? 默认形参会复制一份实参的副本,然后在内部传递,修改等,发生异常,不会赋值给实参,控制权交还调用环境,而实参值不变,还是调用前的值.而使用了NOCOPY ...

  6. git登陆迁移 SourceTree 不能自动识别

    公司切换了迁移了git登陆,具体是什么 我也不是很清楚,结果就是,周一上班 好多小伙伴的git 用不了了,办公室里自然是哀嚎一片, 运维小伙伴给出的解决方案是:改个密码就好啦: 于是照做 结果Sour ...

  7. springboot如何直接读取webapp下页面?

    公司改用springboot的时候,将页面相关的文件都放在了src/main/webapp下,我直接通过main方式启动的时候,无法读取到src/mian/webapp下文件,但是通过spring-b ...

  8. Android中流式布局和热门标签

    1.流式布局特点.应用场景.2.自定义ViewGroup (1)onMeasure:测量子View的宽和高,设置自己的宽和高. (2)onLayout:设置子View的位置. onMeasure:根据 ...

  9. 【BZOJ4547】Hdu5171 小奇的集合 矩阵乘法

    [BZOJ4547]Hdu5171 小奇的集合 Description 有一个大小为n的可重集S,小奇每次操作可以加入一个数a+b(a,b均属于S),求k次操作后它可获得的S的和的最大值.(数据保证这 ...

  10. i o s 崩溃日志分析

    转自:http://blog.csdn.net/totogo2010/article/details/39892467 要分析崩溃日志,首先需要保留发布时的编译出来的.xcarchive文件.这个文件 ...