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)
rest_framework解析器组件源码流程的更多相关文章
- DRF-解析器组件源码解析
解析器组件源码解析 解析器组件源码解析 1 执行request.data 开始找重装的request中的data方法 2 在dispatch找到重装的request def dispatch(self ...
- Django admin组件源码流程
admin 组件 Django 自带的用户后台组件 用于用户便携的操作 admin 组件核心 启动 注册 设计url 启动核心代码 每个app 通过 apps.py 扫描 admin.py 文件 并执 ...
- Django的rest_framework的分页组件源码分析
前言: 分页大家应该都很清楚,今天我来给大家做一下Django的rest_framework的分页组件的分析:我的讲解的思路是这样的,分别使用APIview的视图类和基于ModelViewSet的视图 ...
- DRF之解析器组件及序列化组件
知识点复习回顾一:三元运算 三元运算能够简化我们的代码, 请看如下代码: # 定义两个变量 a = 1 b = 2 # 判断a的真假值,如果为True,则将判断表达式的前面的值赋给c,否则将判断表达 ...
- DRF 解析器组件
Django无法处理application/json协议请求的数据,即,如果用户通过application/json协议发送请求数据到达Django服务器,我们通过request.POST获取到的是一 ...
- Rest_Framework之认证、权限、频率组件源码剖析
一:使用RestFramwork,定义一个视图 from rest_framework.viewsets import ModelViewSet class BookView(ModelViewSet ...
- abp vnext2.0核心组件之领域实体组件源码解析
接着abp vnext2.0核心组件之模块加载组件源码解析和abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析集合.Net Core3.1,基本环境已经完备, ...
- DjangoRestFramework 学习之restful规范 APIview 解析器组件 Postman等
DjangoRestFramework学习一之restful规范.APIview.解析器组件.Postman等 本节目录 一 预备知识 二 restful规范 三 DRF的APIView和解析器组件 ...
- day89 DjangoRsetFramework学习---restful规范,解析器组件,Postman等
DjangoRsetFramework学习---restful规范,解析器组件,Postman等 本节目录 一 预备知识 二 restful规范 三 DRF的APIView和解析 ...
随机推荐
- java基础-集合笔记
Iterator(foreach) 遍历时只能通过iterator去删除(添加)元素,不能直接通过集合对象删除或添加元素 Set HashSet底层是一个HashMap HashSet添加元素,先判断 ...
- uva 465 - Overflow 高精度还是浮点数?
uva 465 - Overflow Overflow Write a program that reads an expression consisting of two non-negativ ...
- 努比亚Z18mini多点对焦
25点对焦 分为了中心对焦.中间对焦.边缘对焦三个区域 [参考文献] 手机上感受单反的“多点对焦”努比亚Z18mini给你想象 https://baijiahao.baidu.com/s?id=160 ...
- TaoKeeper
基于zookeeper的监控管理工具taokeeper,由淘宝团队开源的zk管理中间件: 按照taokeeper官方说明 http://jm-blog.aliapp.com/?p=1450 下载tao ...
- plsql参数
PL/SQL中对out,in out参数使用的? 默认形参会复制一份实参的副本,然后在内部传递,修改等,发生异常,不会赋值给实参,控制权交还调用环境,而实参值不变,还是调用前的值.而使用了NOCOPY ...
- git登陆迁移 SourceTree 不能自动识别
公司切换了迁移了git登陆,具体是什么 我也不是很清楚,结果就是,周一上班 好多小伙伴的git 用不了了,办公室里自然是哀嚎一片, 运维小伙伴给出的解决方案是:改个密码就好啦: 于是照做 结果Sour ...
- springboot如何直接读取webapp下页面?
公司改用springboot的时候,将页面相关的文件都放在了src/main/webapp下,我直接通过main方式启动的时候,无法读取到src/mian/webapp下文件,但是通过spring-b ...
- Android中流式布局和热门标签
1.流式布局特点.应用场景.2.自定义ViewGroup (1)onMeasure:测量子View的宽和高,设置自己的宽和高. (2)onLayout:设置子View的位置. onMeasure:根据 ...
- 【BZOJ4547】Hdu5171 小奇的集合 矩阵乘法
[BZOJ4547]Hdu5171 小奇的集合 Description 有一个大小为n的可重集S,小奇每次操作可以加入一个数a+b(a,b均属于S),求k次操作后它可获得的S的和的最大值.(数据保证这 ...
- i o s 崩溃日志分析
转自:http://blog.csdn.net/totogo2010/article/details/39892467 要分析崩溃日志,首先需要保留发布时的编译出来的.xcarchive文件.这个文件 ...