Django Rest Framework源码剖析(五)-----解析器

<table style="height: 30px; background-color: #afeeee; width: 1266px; ; width: 1266px;" border="0"><tr>
<td><span style="font-size: 16px;">一、简介</td>
</tr></table>

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

二、基本使用1.json解析器

同样以订单视图为例,添加json解析器,如下:

rest_framework.versioning rest_framework.parsers ==</span><span style="color: #0000ff;"&gt;def</span> get(self,request,*args,**<span style="color: #000000;"&gt;kwargs): res</span>={<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;name</span><span style="color: #800000;"&gt;"</span>:<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;wd</span><span style="color: #800000;"&gt;"</span>,<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;age</span><span style="color: #800000;"&gt;"</span>:22<span style="color: #000000;"&gt;} </span><span style="color: #0000ff;"&gt;return</span> JsonResponse(res,safe=<span style="color: #000000;"&gt;True) </span><span style="color: #0000ff;"&gt;def</span> post(self,**<span style="color: #000000;"&gt;kwargs): </span><span style="color: #0000ff;"&gt;print</span>(request.data) <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;获取解析后的请求结果</span> <span style="color: #0000ff;"&gt;return</span> JsonResponse({<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;success</span><span style="color: #800000;"&gt;"</span>:<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;ok</span><span style="color: #800000;"&gt;"</span>},safe=True)</pre>

使用postman向http://127.0.0.1:8000/api/v1/user视图发送json数据,注意请求头必须是application/json,如下图:

查看post结果(结果直接是json格式):

2.form表单解析器

视图

rest_framework.versioning rest_framework.parsers = versioning_class =</span><span style="color: #0000ff;"&gt;def</span> get(self,safe=<span style="color: #000000;"&gt;True) </span><span style="color: #0000ff;"&gt;def</span> post(self,safe=True)</pre>

使用postman发送form表单数据

后台接受,并且结果已经转化为QueryDict类型了

<table style="height: 30px; background-color: #afeeee; width: 1266px; ; width: 1266px;" border="0">

<tr>
<td><span style="font-size: 16px;">三、源码剖析</td>
</tr></table>

1.根据以上示例,梳理解析器解析数据流程

  • 获取用户请求
  • 获取用户请求体
  • 根据用户请求头信息和parase_classes=[...],中的请求头进行比较,匹配上请求头就使用该解析器处理
  • 解析器从请求体中拿数据进行处理,处理完成之后将结果返回给request.data

2.源码剖析:

同样和一样,请求进来,先执行APIView的dispatch方法,以下是源码,分析请看注解

dispatch方法:

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

get_parsers()源码,和认证、权限一样,解析器采用列表生成式返回解析器对象的列表,所以示例中定义解析器的变量是parser_classes:

self.praser_classes,默认(全局)配置

当调用request.data获取请求数据时候将使用解析器,下面是request.data源码:

执行self._load_data_and_files(),获取请求数据或者文件数据,self._load_data_and_files()源码:

执行self._prase()方法,获取解析器,并对请求的Content-Type进行解析,选择解析器,返回解析后的数据,以下是self._prase源码:

May raise an `UnsupportedMediaType`,or `ParseError` exception. </span><span style="color: #800000;"&gt;"""</span><span style="color: #000000;"&gt; media_type </span>=<span style="color: #000000;"&gt; self.content_type <span style="color: #ff6600;"&gt;#获取请求体中的Content-Type </span></span><span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt;: stream </span>=<span style="color: #000000;"&gt; self.stream <span style="color: #ff6600;"&gt;#如果是文件数据,则获取文件流数据 </span></span><span style="color: #0000ff;"&gt;except</span><span style="color: #000000;"&gt; RawPostDataException: </span><span style="color: #0000ff;"&gt;if</span> <span style="color: #0000ff;"&gt;not</span> hasattr(self._request,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;_post</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;): </span><span style="color: #0000ff;"&gt;raise</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; If request.POST has been accessed in middleware,and a method='POST'</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; request was made with 'multipart/form-data',then the request stream</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; will already have been exhausted.</span> <span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; self._supports_form_parsing(): </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; (self._request.POST,self._request.FILES<span style="color: #ff6600;"&gt;) #处理文件类型数据</span> stream </span>=<span style="color: #000000;"&gt; None </span><span style="color: #0000ff;"&gt;if</span> stream <span style="color: #0000ff;"&gt;is</span> None <span style="color: #0000ff;"&gt;or</span> media_type <span style="color: #0000ff;"&gt;is</span><span style="color: #000000;"&gt; None: </span><span style="color: #0000ff;"&gt;if</span> media_type <span style="color: #0000ff;"&gt;and</span><span style="color: #000000;"&gt; is_form_media_type(media_type): empty_data </span>= QueryDict(<span style="color: #800000;"&gt;''</span>,encoding=<span style="color: #000000;"&gt;self._request._encoding) </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt;: empty_data </span>=<span style="color: #000000;"&gt; {} empty_files </span>=<span style="color: #000000;"&gt; MultiValueDict() </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; (empty_data,empty_files) parser </span>=<span style="color: #000000;"&gt; self.negotiator.select_parser(self,self.parsers) <span style="color: #ff6600;"&gt;#选择解析器, </span></span><span style="color: #0000ff;"&gt;if</span> <span style="color: #0000ff;"&gt;not</span><span style="color: #000000;"&gt; parser: </span><span style="color: #0000ff;"&gt;raise</span><span style="color: #000000;"&gt; exceptions.UnsupportedMediaType(media_type) </span><span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt;: parsed </span>=<span style="color: #000000;"&gt; parser.parse(stream,media_type,self.parser_context) <span style="color: #ff6600;"&gt;#执行解析器的parse方法(从这里可以看出每个解析器都必须有该方法),对请求数据进行解析 </span></span><span style="color: #0000ff;"&gt;except</span><span style="color: #000000;"&gt; Exception: </span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; If we get an exception during parsing,fill in empty data and</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; re-raise. Ensures we don't simply repeat the error when</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; attempting to render the browsable renderer response,or when</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; logging the request or similar.</span> self._data = QueryDict(<span style="color: #800000;"&gt;''</span>,encoding=<span style="color: #000000;"&gt;self._request._encoding) self._files </span>=<span style="color: #000000;"&gt; MultiValueDict() self._full_data </span>=<span style="color: #000000;"&gt; self._data </span><span style="color: #0000ff;"&gt;raise</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; Parser classes may return the raw data,or a</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; DataAndFiles object. Unpack the result as required.</span> <span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt;: </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; (parsed.data,parsed.files) <span style="color: #ff6600;"&gt; #返回解析结果,元祖,解析后的数据在parsed.data(在load_data_and_files中使用self._data和self._files进行接受),                                文件数据在parsed.files中 </span></span><span style="color: #0000ff;"&gt;except</span><span style="color: #000000;"&gt; AttributeError: empty_files </span>=<span style="color: #000000;"&gt; MultiValueDict() </span><span style="color: #0000ff;"&gt;return</span> (parsed,empty_files)</pre>

以上就是整个django rest framework 解析器源码,下面我们来看看示例中json解析器的源码,说明请看注解:

= ==</span><span style="color: #0000ff;"&gt;def</span> parse(self,stream,media_type=None,parser_context=<span style="color: #000000;"&gt;None): <span style="color: #ff6600;"&gt;#在源码中解读过,该方法用于解析请求体 </span></span><span style="color: #800000;"&gt;"""</span><span style="color: #800000;"&gt; Parses the incoming bytestream as JSON and returns the resulting data. </span><span style="color: #800000;"&gt;"""</span><span style="color: #000000;"&gt; parser_context </span>= parser_context <span style="color: #0000ff;"&gt;or</span><span style="color: #000000;"&gt; {} encoding </span>= parser_context.get(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;encoding</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,settings.DEFAULT_CHARSET) </span><span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt;: decoded_stream </span>=<span style="color: #000000;"&gt; codecs.getreader(encoding)(stream) parse_constant </span>= json.strict_constant <span style="color: #0000ff;"&gt;if</span> self.strict <span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt; None </span><span style="color: #0000ff;"&gt;return</span> json.load(decoded_stream,parse_constant=<span style="color: #000000;"&gt;parse_constant) <span style="color: #ff6600;"&gt;#本质使用json类进行解析 </span></span><span style="color: #0000ff;"&gt;except</span><span style="color: #000000;"&gt; ValueError as exc: </span><span style="color: #0000ff;"&gt;raise</span> ParseError(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;JSON parse error - %s</span><span style="color: #800000;"&gt;'</span> % six.text_type(exc))</pre>
1.解析器本质:

django rest framework解析本质是根据请求头中的Content-Type来实现,不同的类型使用不同的解析器,一个视图可有多个解析器。

2.使用:

REST_FRAMEWORK =</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;解析器</span> <span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;DEFAULT_PARSER_CLASSES</span><span style="color: #800000;"&gt;"</span>:[<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;rest_framework.parsers.JSONParser</span><span style="color: #800000;"&gt;"</span>,<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;rest_framework.parsers.FormParser</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;]

}

<span style="color: #008000;">#<span style="color: #008000;">单一视图使用
parser_classes = [JSONParser,FormParser]

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


注:所有源代码均实测运行过。所有源代码均已上传CSDN,请有需要的朋友自行下载。
继承APIView和ViewSetMixin;作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。ViewSet在开发接口中不经常用。
一、Django介绍Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。Django 是一个开放源代码的 Web 应用框架,由 Python 写成。Django 遵守 BSD 版权,初次发布于 2005 年 7 月, 并于 2008 年 9 月发布了第一个正式版本 1.0 。Django学习线路Django 采用了 MVT 的软件设计模式,即模型(Model),视图(View)和模板(Template)。这个MVT模式并
本文从nginx快速掌握到使用,gunicorn快速掌握到使用,实现小白快速搭建django项目,并对可能出现的报错进行了分析
uniapp微信小程序订阅消息发送服务通知
Django终端打印SQL语句 1 Setting配置: 2 默认python 使用的MysqlDB连接,Python3 支持支持pymysql 所有需要在app里面的__init__加上下面配置:
url: re_path(&#39;authors/$&#39;, views.AuthorView.as_view()), re_path(&#39;book/(?P\d+)/$&#39;, vie
前提 关于html寻找路线: template 如果在各个APP中存在, Django 会优先找全局template 文件下的html文件,如果全局下的template文件没有相关的html Djan
// GET请求request.GET // POST请求request.POST // 处理文件上传请求request.FILES // 处理如checkbox等多选 接受列表request.get
from bs4 import BeautifulSoup#kindeditordef kindeditor(request): s = &#39;&#39;&#39; &lt;li&gt;&lt;s
view.py 配置 html 配置
from django.http import JsonResponse JsonResponse 里面代码会加这一个响应头 kwargs.setdefault(&#39;content_type&#
#下面两种是基于QuerySet查询 也就是说SQL中用的jion连表的方式查询books = models.UserInfo.objects.all() print(type(books)) &gt
return HttpResponse(&quot;OK&quot;) 返回一个字符串 return redirect(&quot;/index/&quot;) 返回URL return render
from django.http import JsonResponse JsonResponse 里面代码会加这一个响应头 kwargs.setdefault(&#39;content_type&#
浏览器有一个很重要的概念——同源策略(Same-Origin Policy)。所谓同源是指,域名,协议,端口相同。不同源的客户端脚本(javascript、ActionScript)在没明确授权的情况
自动发送 &gt; 依赖jQuery文件 实例--&gt;GET请求: 手动发送 &gt; 依赖浏览器XML对象(也叫原生ajax) Ajax主要就是使用 【XmlHttpRequest】对象来完成请
#下面两种是基于QuerySet查询 也就是说SQL中用的jion连表的方式查询books = models.UserInfo.objects.all() print(type(books)) &gt
// GET请求request.GET // POST请求request.POST // 处理文件上传请求request.FILES // 处理如checkbox等多选 接受列表request.get
return HttpResponse(&quot;OK&quot;) 返回一个字符串 return redirect(&quot;/index/&quot;) 返回URL return render