加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

发布时间:2020-12-15 17:16:56 所属栏目:大数据 来源:网络整理
导读:table style="height: 30px; background-color: #afeeee; width: 1266px; ; width: 1266px;" border="0" tr td span style="font-size: 16px;"一、简介 /td /tr /table 解析器顾名思义就是对请求体进行解析。为什么要有解析器?原因很简单,当后台和前端进行
<tr>
<td><span style="font-size: 16px;">一、简介</td>
</tr></table>

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

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

二、基本使用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方法:

dispatch(self,**== request = self.initialize_request(request,**== self.default_response_headers
    <span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt;:
        self.initial(request,</span>*args,**<span style="color: #000000;"&gt;kwargs)

        </span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; Get the appropriate handler method</span>
        <span style="color: #0000ff;"&gt;if</span> request.method.lower() <span style="color: #0000ff;"&gt;in</span><span style="color: #000000;"&gt; self.http_method_names:
            handler </span>=<span style="color: #000000;"&gt; getattr(self,request.method.lower(),self.http_method_not_allowed)
        </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt;:
            handler </span>=<span style="color: #000000;"&gt; self.http_method_not_allowed

        response </span>= handler(request,**<span style="color: #000000;"&gt;kwargs)

    </span><span style="color: #0000ff;"&gt;except</span><span style="color: #000000;"&gt; Exception as exc:
        response </span>=<span style="color: #000000;"&gt; self.handle_exception(exc)

    self.response </span>= self.finalize_response(request,response,**<span style="color: #000000;"&gt;kwargs)
    </span><span style="color: #0000ff;"&gt;return</span> self.response</pre>

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

initialize_request(self,**= self.get_parser_context(request) =self.get_parsers(), authenticators===

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

[parser() parser self.parser_classes]

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

</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; The following policies may be set at either globally,or per-view.</span> renderer_classes =<span style="color: #000000;"&gt; api_settings.DEFAULT_RENDERER_CLASSES

<span style="color: #ff6600;"> parser_classes <span style="color: #ff6600;">=<span style="color: #000000;"><span style="color: #ff6600;"> api_settings.DEFAULT_PARSER_CLASSES #解析器全局配置
authentication_classes =<span style="color: #000000;"> api_settings.DEFAULT_AUTHENTICATION_CLASSES
throttle_classes =<span style="color: #000000;"> api_settings.DEFAULT_THROTTLE_CLASSES
permission_classes =<span style="color: #000000;"> api_settings.DEFAULT_PERMISSION_CLASSES
content_negotiation_class =<span style="color: #000000;"> api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
metadata_class =<span style="color: #000000;"> api_settings.DEFAULT_METADATA_CLASS
versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

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

_hasattr(self, self._full_data

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

_hasattr(self,= self._parse() self._full_data == </span></span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; if a form media type,copy data &amp; files refs to the underlying</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; http request so that closable objects are handled appropriately.</span> <span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; is_form_media_type(self.content_type): self._request._post </span>=<span style="color: #000000;"&gt; self.POST self._request._files </span>= self.FILES</pre>

执行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]

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读