1 绪论

  网络传输数据只能传输字符串格式的,如果是列表、字典等数据类型,需要转换之后才能使用但是我们之前的rest_framework例子都没有转换就直接可以使用了,这是因为rest_framework自带有一套解析器。

2 源码分析

  我们重新回到dispatch方法中对请求进行重新封装的initialize_request类,源码如下:

def initialize_request(self, request, *args, **kwargs):

        """

        Returns the initial request object.

        """

        print('initialize_request方法执行:封装request开始')

        parser_context = self.get_parser_context(request)

        return Request(

            request,

            parsers=self.get_parsers(),#获取所有解析器,并实例化

            authenticators=self.get_authenticators(),

            negotiator=self.get_content_negotiator(),

            parser_context=parser_context

        )

  源码中调用了一个get_parsers方法,这个类返回的是项目中配置的所有解析器类实例化对象组成的列表,源码如下:

 def get_parsers(self):
return [parser() for parser in self.parser_classes]

  get_parsers方法采用列表生成式的方式遍历了配置的所有解析器类,并进行实例化,与认证、权限等实例化操作一般无二。所以,在重新封装request的时候,rest_framework就把解析器类实例封装进了request中,但是与认证、权限等环节不懂的是,解析操作并不是在dispatch函数执行过程中完成。请看如下代码:

class QarserView(APIView):

    parser_classes = [JSONParser ,]

    def post(self , request , *args , **kwargs):

        print(request.data)#解析器开始执行

        return HttpResponse(request.data)

  也就是说,只有当视图中调用了request.data的时候,解析器才会真正开始运转起来。这里的data是封装在rest_framework的Request中的一个方法,源码如下:

@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data

  关键是其中的_load_data_and_files方法,如下所示:

def _load_data_and_files(self):
if not _hasattr(self, '_data'):
self._data, self._files = self._parse()#解析出来的数据
if self._files:
self._full_data = self._data.copy()
self._full_data.update(self._files)
else:
self._full_data = self._data #如果是一个表单数据
if is_form_media_type(self.content_type):
self._request._post = self.POST
self._request._files = self.FILES

  _parse方法:

def _parse(self):
media_type = self.content_type#获取用户提交的请求头的content_type
try:
stream = self.stream#获取request请求体
except RawPostDataException:
if not hasattr(self._request, '_post'):
raise
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)#返回一个QueryDict对象,内容为{空
else:
empty_data = {}
empty_files = MultiValueDict()
return (empty_data, empty_files)
#media_type不为空时就挑选解析器,用media_type与配置的每个解析类的media_type对比
parser = self.negotiator.select_parser(self, self.parsers)#得到相匹配的解析器对象
if not parser:#如果没有相匹配的解析器,抛出异常
raise exceptions.UnsupportedMediaType(media_type)
try:#执行解析器实例对象的parse方法
parsed = parser.parse(stream, media_type, self.parser_context)
except Exception:
self._data = QueryDict('', encoding=self._request._encoding)
self._files = MultiValueDict()
self._full_data = self._data
raise
try:
return (parsed.data, parsed.files)#返回解析后的数据
except AttributeError:
empty_files = MultiValueDict()
return (parsed, empty_files)

  在这个_parse方法中,就调用了解析器类的parse方法,下面的是JSONParser中的parse方法:

def parse(self, stream, media_type=None, parser_context=None):

    parser_context = parser_context or {}

    encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)

    try:
decoded_stream = codecs.getreader(encoding)(stream)#解码 parse_constant = json.strict_constant if self.strict else None#转化为json数据 return json.load(decoded_stream, parse_constant=parse_constant) except ValueError as exc: raise ParseError('JSON parse error - %s' % six.text_type(exc))

parse解析取得json数据后,层层网上返回,最终在request.data中输出json数据。

3 配置方法

  局部配置:

  只用到的试图类中加入以下代码:

parser_classes = [JSONParser ,]

  全局配置:

  在settings.py文件中配置

REST_FRAMEWORK = {

    "DEFAULT_PARSER_CLASSES":[

        'rest_framework.parsers.JSONParser' ,

        'rest_framework.parsers.FormParser' ,
] }

六、django rest_framework源码之解析器剖析的更多相关文章

  1. 一、django rest_framework源码之总体流程剖析

    1 序言 有如下django代码,视图层: from django.http import HttpResponse from rest_framework.views import APIView ...

  2. 二、django rest_framework源码之认证流程剖析

    1 绪言 上一篇中讲了django rest_framework总体流程,整个流程中最关键的一步就是执行dispatch方法.在dispatch方法中,在调用了一个initial方法,所有的认证.权限 ...

  3. 三、django rest_framework源码之权限流程剖析

    1 绪言 上一篇中分析了认证部分的源码,认证后的下一个环节就是权限判定了.事实上,权限判定肯定要与认证联合使用才行,因为认证部分不会对请求进行禁止或者是允许,而只是根据请求中用户信息进行用户身份判断, ...

  4. (一) Mybatis源码分析-解析器模块

    Mybatis源码分析-解析器模块 原创-转载请说明出处 1. 解析器模块的作用 对XPath进行封装,为mybatis-config.xml配置文件以及映射文件提供支持 为处理动态 SQL 语句中的 ...

  5. 四、django rest_framework源码之频率控制剖析

    1 绪言 权限判定之后的下一个环节是访问频率控制,本篇我们分析访问频率控制部分源码. 2 源码分析 访问频率控制在dispatch方法中的initial方法调用check_throttles方法开始. ...

  6. 七、django rest_framework源码之视图

    1 绪言 当大家看大这篇博文的时候,应该对Django rest_framework中的CBV有所了解了,大致来说就是通过定义类来继承APIView类,并在类中定义get.post.put.delet ...

  7. 五、django rest_framework源码之版本控制剖析

    1 绪论 Djangorest_framework的版本控制允许用户更改不同客户端之间的行为,且提供了许多不同的版本控制方案.版本控制由传入的客户端请求确定,可以基于请求URL,也可以基于请求标头. ...

  8. Django与drf 源码视图解析

    0902自我总结 Django 与drf 源码视图解析 一.原生Django CBV 源码分析:View """ 1)as_view()是入口,得到view函数地址 2) ...

  9. Django settings源码解析

    Django settings源码 Django中有两个配置文件 局部配置:配置文件settings.py,即项目同名文件夹下的settings.py文件 全局配置:django内部全局的配置文件se ...

随机推荐

  1. 重新找回spyder3-editor 里的code completion

    升级到spyder3之后, 突然丢失了code autocompletion在editor context里. 觉得太不爽了. 虽然在ipython窗格里TAB键的自动完成功能依然完好. 仔细观察 T ...

  2. Linux下编译Phantomjs

    1.安装依赖的库 <pre> sudo apt-get install g++ flex bison gperf ruby perl \ libsqlite3-dev libfontcon ...

  3. WPF控件收集

    1.Extended WPF Toolkit 2.Fluent Ribbon Control Suite 3.WPF Ribbon Control 4.Telerik RadControls for ...

  4. 【leetcode 简单】 第六十七题 回文链表

    请判断一个链表是否为回文链表. 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true 进阶: 你能否用 O(n) 时间复 ...

  5. JavaScript常用数组方法

    JavaScript数组方法有以下这些: forEach() 方法对数组的每一个元素执行一次提供的函数. map() 方法创建一个新数组,其结果是该数组都执行一次函数,原函数保持不变. filter( ...

  6. 20165329 Java实验二:面向对象编程

    实验内容: 面向对象程序设计-1 实验要求: 提交最后三个JUnit测试用例(正常情况,错误情况,边界情况)都通过的截图 实验步骤: 1.按照老师博客的要求新建一个MyUtil项目 在src内新建ja ...

  7. Python标准库笔记(10) — itertools模块

    itertools 用于更高效地创建迭代器的函数工具. itertools 提供的功能受Clojure,Haskell,APL和SML等函数式编程语言的类似功能的启发.它们的目的是快速有效地使用内存, ...

  8. JVM常用启动参数+常用内存调试工具

    一.JVM常用启动参数 -Xms:设置堆的最小值. -Xmx:设置堆的最大值. -Xmn:设置新生代的大小. -Xss:设置每个线程的栈大小. -XX:NewSize:设置新生代的初始值. -XX:M ...

  9. iOS开发之删除Provisioning Profiles方法

    1.在finder下打开go -> go to folder输入: ~/Library/MobileDevice/Provisioning Profiles 2.查看上面的列表,按照时间顺序删除 ...

  10. 27 Debugging Go Code with GDB 使用GDB调试go代码

    Debugging Go Code with GDB  使用GDB调试go代码 Introduction Common Operations Go Extensions Known Issues Tu ...