DRF从入门到精通三(反序列化数据校验源码分析、断言Assert、DRF之请求、响应)

文章目录

  • 一、反序列化数据校验源码分析
  • 二、断言Assert
  • 三、DRF之请求、响应
    • Request类和Response类
    • 请求中的Request 能够解析前端传入的编码格式
    • 响应中的Response能够响应的编码格式

一、反序列化数据校验源码分析

反序列化数据校验,校验顺序为:先校验字段自己的规则(最大、最小),然后是局部钩子,然后是全局钩子

  1. 反序列化校验开始
    在视图类中的s_valid()被执行时,就会进行反序列化的校验,校验通过返回True,否则返回False

  2. 反序列化的过程

    • ser.is_valid()是序列化类的对象,假设序列化类是BookSerializer,当执行is_valid时。首先在序列化类产生的对象中查找,当找不到就会去找到它的父类中找,结果在它父类的父类中找到了BaseSerializer
	BaseSerializer类
	 def is_valid(self, *, raise_exception=False):
	 	'断言检查,确保类的实例中具有名为initial_data的属性,如果没有就引发下面这段话包含的特定的错误信息'
        assert hasattr(self, 'initial_data'), (
            'Cannot call `.is_valid()` as no `data=` keyword argument was '
            'passed when instantiating the serializer instance.'
        )
		
        if not hasattr(self, '_validated_data'):
        	'''
            self序列化类的对象,属性中没有_validated_data,就一定会走这句
           	并且只要走过一次后,下一次就无需再次走了,它优化了is_valid被多次调用,只会走一次校验
           	'''
            try:
            	'真正的走校验,一旦执行了这里,以后self中就有了_validated_data'
            	'''
				然后我们就得去看看这个self.run_validation(self.initial_data)
				我们不能直接按住ctrl键点击,因为它会从当前类中找run_validation,
				我们得清楚,这个self是谁,它还是我们的视图类,所以我们得返回到视图类从它一步一步往它继承的类中找
				清楚如何查找后,我们就从视图类----》serializer.Serializer(找到了,为什么从这个里面找因为
				我们就是使用serializer.Serializer类的)
				'''
                self._validated_data = self.run_validation(self.initial_data)
                '''
                这下面的是当校验不通过时,执行的,会给_validatad_data设置为一个空字段,
                并且给_errors设置为验证错误的详细信息
                '''
            except ValidationError as exc:
                self._validated_data = {}
                self._errors = exc.detail
            else:
                self._errors = {}
        return not bool(self._errors)


		通过上面self.run_validation(self.initial_data)我们找到了下面这块源码,
		而这里的run_validatiion方法就是DRF序列化器验证过程中的核心
		
		def run_validation(self, data=empty):
			'''
			局部钩子的执行,这里的self就还是视图类的对象
			data就是前端传入的数据,value是前端传入,字段自己校验通过的字典
			'''
	        value = self.to_internal_value(data)
	        try:
	        	'这个是字段验证器'
	        	self.run_validators(value)
	        	'''
	        	这个是全局钩子的执行,和上面一样self是视图类的对象,如果我们在序列化其中写了全局钩子,
	        	那么就优先使用我们自己定义的全局钩子,如果没写则执行父类的,(serializer.Serializer)
	        	结果可以看到父类根本就没有做校验
	        	    def validate(self, attrs):
       					 return attrs
	        	'''
	            value = self.validate(value)  #运行自定义验证方法
	            '确保自定义验证方法返回了验证后的数据'
	            assert value is not None, '.validate() should return the validated data'
	        except (ValidationError, DjangoValidationError) as exc:
	        # 捕获验证过程中可能引发的异常,并转换为DRF的ValidationError
	            raise ValidationError(detail=as_serializer_error(exc))
			# 返回验证后的数据
	        return value
		
		看完了全局钩子后我们在看一下局部钩子的self.to_internal_value(data),也是一样的思路,从视图类找,
		视图类肯定没有,然后找父类serializer结果就是这个页面的
		def to_internal_value(self, data):
			ret = OrderedDict()# 用于存储验证后的数据
	        errors = OrderedDict()# 用于存储字段验证过程中的错误信息
	        fields = self._writable_fields# 获取序列化器中的所有字段
	       '序列化类中所有的字段,for循环每次取一个字段对象。例如name=CharField()'
	        for field in fields: 
	        '''去视图类的对象中反射,validate_字段名的方法,如果有就执行,没有就不执行'''
	            validate_method = getattr(self, 'validate_' + field.field_name, None)
	            primitive_value = field.get_value(data)
	            try:
	            	'这句话就是字段自己的校验规则(最长最短长度等)'
	                validated_value = field.run_validation(primitive_value)
	                '局部钩子,如果在序列化类中写了局部钩子验证规则,就运行自己写的'
	                if validate_method is not None:
	                	'执行局部钩子,传入当前字段的value值'
	                    validated_value = validate_method(validated_value)
	                    
	            '如果抛异常了就会被捕获'
	            except ValidationError as exc:
	            	'捕获DRF的ValidationError异常'
	                errors[field.field_name] = exc.detail
				
	            except DjangoValidationError as exc:
	            	'捕获Django的ValidationError异常'
	                errors[field.field_name] = get_error_detail(exc)
	            except SkipField:
	            	'如果遇到SkipField异常,就跳过该字段的处理'
	                pass
	            else:
	            	'如果没有异常,将验证后的值设置到结果中'
	                set_value(ret, field.source_attrs, validated_value)
	
	        if errors:
	            raise ValidationError(errors)
	
	        return ret

这里提一下如何追源码,查看下面两张图即可。
在这里插入图片描述
在这里插入图片描述

二、断言Assert

	'''普通写法'''
	name = 'jack1'
	if not name == 'jack':
		raise Exception('name不登录jack')
	
	
	'''断言写法'''
	'assert 后写条件,只要不符合条件,就会跑AssertionErro异常,后面写异常信息'
	name = 'tom'
	assert name == 'tom','name不是tom'
	print('程序执行完毕!')

	
	'源码中使用'
	assert value is not None, '.validate() should return the validated data'

三、DRF之请求、响应

Request类和Response类

Request类

REST FrameWork传入视图的Request对象不再是Django默认的HttpRequest对象
而是REST FrameWork提供的扩展了HttpResponse类的Request类的对象了
Rest FrameWork提供了Parser解析器 在接收到请求后自动根据Content-type指明的数据类型(默认是JSON)
将请求数据进行Parse解析 解析为字典[QueryDict]对象保存到Request对象
Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果
无论前端发送的哪种格式数据 我们都可以用同一个一种方式读取数据

属性data
request.data返回解析之后的请求题数据 类似于Django中的request.POSTrequest.FILES属性

  • 包含了解析之后的文件和非文件数据
  • 包含了对POST、PUT、PATCH请求方式解析后的数据
  • 利用了REST FrameWork的Parsers解析器 不仅仅支持表单类型数据 也支持JSON数据

属性query_params
request.query_params与Django标准的request.GET相同 只是更换了更正确的名称


Response类

	Response(data=None, status=None,template_name=None, headers=None,exception=False, content_type=None)

REST FrameFork提供了一个响应类Response使用该类构造响应对象时 响应的具体数据内容会被转换(render渲染)成符合前端需求的类型
REST FrameFork提供了Renderer渲染器 用来根据请求投中的Accept接收数据类型声明 来自动转换响应数据到对应格式 如果前端请求中未进行Accept声明 则会采用默认方式处理响应数据
我们可以通过配置来修改默认响应格式 可以在rest_framework.settings查找所有的drf默认配置项

	REST_FRAMEWORK = {
	    'DEFAULT_RENDERER_CLASSES': (   # 默认响应渲染类
	        'rest_framework.renderers.JSONRenderer',    # JSON渲染器
	        'rest_framework.renderers.BrowsableAPIRenderer',    # 浏览器API渲染器
	    )
	}

参数说明:

  • data 为响应准备的序列化处理后的数据
  • status 状态码默认200
  • template_name 模版名称 如果使用HTML Renderer时需要指定
  • headers 用于存放响应头信息的字典
  • content_type 响应数据的Content_type 通常此参数无需传递 REST FrameWork会根据前端所需类型数据来设置该参数

常用属性

  • data 传给response对象的序列化后 但还没有给render处理的数据
  • status_code 状态码数字
  • content 经过render处理后的响应数据

状态码
为了方便设置状态码,REST framewrok在rest_framework.status模块中提供了常用状态码常量。
1)信息告知 - 1xx

	HTTP_100_CONTINUE
	HTTP_101_SWITCHING_PROTOCOLS

2)成功 - 2xx

	HTTP_200_OK
	HTTP_201_CREATED
	HTTP_202_ACCEPTED
	HTTP_203_NON_AUTHORITATIVE_INFORMATION
	HTTP_204_NO_CONTENT
	HTTP_205_RESET_CONTENT
	HTTP_206_PARTIAL_CONTENT
	HTTP_207_MULTI_STATUS

3)重定向 - 3xx

	HTTP_300_MULTIPLE_CHOICES
	HTTP_301_MOVED_PERMANENTLY
	HTTP_302_FOUND
	HTTP_303_SEE_OTHER
	HTTP_304_NOT_MODIFIED
	HTTP_305_USE_PROXY
	HTTP_306_RESERVED
	HTTP_307_TEMPORARY_REDIRECT

4)客户端错误 - 4xx

	HTTP_400_BAD_REQUEST
	HTTP_401_UNAUTHORIZED
	HTTP_402_PAYMENT_REQUIRED
	HTTP_403_FORBIDDEN
	HTTP_404_NOT_FOUND
	HTTP_405_METHOD_NOT_ALLOWED
	HTTP_406_NOT_ACCEPTABLE
	HTTP_407_PROXY_AUTHENTICATION_REQUIRED
	HTTP_408_REQUEST_TIMEOUT
	HTTP_409_CONFLICT
	HTTP_410_GONE
	HTTP_411_LENGTH_REQUIRED
	HTTP_412_PRECONDITION_FAILED
	HTTP_413_REQUEST_ENTITY_TOO_LARGE
	HTTP_414_REQUEST_URI_TOO_LONG
	HTTP_415_UNSUPPORTED_MEDIA_TYPE
	HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
	HTTP_417_EXPECTATION_FAILED
	HTTP_422_UNPROCESSABLE_ENTITY
	HTTP_423_LOCKED
	HTTP_424_FAILED_DEPENDENCY
	HTTP_428_PRECONDITION_REQUIRED
	HTTP_429_TOO_MANY_REQUESTS
	HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
	HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS

5)服务器错误 - 5xx

	HTTP_500_INTERNAL_SERVER_ERROR
	HTTP_501_NOT_IMPLEMENTED
	HTTP_502_BAD_GATEWAY
	HTTP_503_SERVICE_UNAVAILABLE
	HTTP_504_GATEWAY_TIMEOUT
	HTTP_505_HTTP_VERSION_NOT_SUPPORTED
	HTTP_507_INSUFFICIENT_STORAGE
	HTTP_511_NETWORK_AUTHENTICATION_REQUIRED

请求中的Request 能够解析前端传入的编码格式

方式一 局部配置

在继承APIView及其子类的的视图类中配置

	from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
	class BookView(APIView):
	    parser_classes = [JSONParser,]

方式二全局配置
在配置文件中配置(影响所有,全局配置)

  • django项目有默认配置,每个项目有独立的一个配置文件
	from django.conf import settings
	from djangoday01 import settings
  • drf有默认配置,每个项目有独立的一个配置文件---->>>django的配置文件中
	from rest_framework import settings
	from drf_day05 import settings

	REST_FRAMEWORK = {
	    'DEFAULT_PARSER_CLASSES': [
	 	   'rest_framework.parsers.JSONParser',  # 默认json默认
	 	   'rest_framework.parsers.FormParser',  # 默认urlencoded编码
	 	   'rest_framework.parsers.MultiPartParser', # 默认form_data编码
	    ],
	}

方式三

如果全局配了1个,某个视图类想要3个,如何配置?

  1. 全局配置不用动,只需要在视图类中配置能够解析前端数据的3种编码格式
  2. 视图类中,查询的顺序:视图类自身——>项目drf配置——>drf默认配置

响应中的Response能够响应的编码格式

方式一
在视图类中写-----局部配置

	# 响应格式
	from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
	class BookView(APIView):
	    renderer_classes=[JSONRenderer,]

方式二
在项目配置文件中写—全局配置

	REST_FRAMEWORK = {
	    'DEFAULT_RENDERER_CLASSES': [
	        'rest_framework.renderers.JSONRenderer',
	        'rest_framework.renderers.BrowsableAPIRenderer',
	    ],
	}

方式三

使用顺序(一般就用内置的即可)。使用顺序:视图类自身配置——>项目drf配置——>drf默认内置的配置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/265789.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

懂机器学习?先来回答这三个问题 >>

机器学习是一种数据分析技术,让计算机学习人类和动物与生俱来的能力:从经验中学习。 机器学习算法使用计算方法直接从数据中“学习”信息,而不依赖于预定方程作为模型。 随着可用于学习的样本数量的增加,算法也会相应地提高性能。…

探索栈数据结构:深入了解其实用与实现(c语言实现栈)

上次结束了链表部分的内容:链接未来:深入理解链表数据结构(二.c语言实现带头双向循环链表) 然而,当我们涉及特定问题时,另一个非常有用的数据结构也开始显得至关重要——栈 栈与链表有着截然不同的特性&a…

MySQL数据库基础和基本的增删改查操作

目录 前瞻 数据库的基本概念 数据库管理系统(DBMS) 数据库系统(DBS) 数据库类型和常用数据库 关系型数据库 SQL 非关系型数据库 NoSQL SQL语句 简介 SQL语句分类 常用的数据类型 MySQL的六大约束特性 SQL语句的使用 创建及删除数据库和表 …

H5小游戏加固方案

今年的中国游戏产业年会上,小游戏成了万众瞩目的行业新风口。据伽马数据统计:2023年小游戏市场规模可达200亿元,同比增长300% 。 小游戏有着分发更精准、用户转化率更高、研发成本更低、场景适用性更强等优势,具备巨大的市场潜力…

openGauss学习笔记-171 openGauss 数据库运维-备份与恢复-导入数据-深层复制

文章目录 openGauss学习笔记-171 openGauss 数据库运维-备份与恢复-导入数据-深层复制171.1 使用CREATE TABLE执行深层复制171.1.1 操作步骤 171.2 使用CREATE TABLE LIKE执行深层复制171.2.1 操作步骤 171.3 通过创建临时表并截断原始表来执行深层复制171.3.1 操作步骤 openGa…

服务器数据恢复-昆腾存储StorNext文件系统下raid5数据恢复案例

服务器数据恢复环境: 昆腾某型号存储,StorNext文件存储系统。 共有9个分别配置了24块磁盘的磁盘柜,其中8个磁盘柜存放普通数据,1个磁盘柜存放元数据。 存放元数据的磁盘柜中的24块磁盘组建了8组RAID1阵列和1组4盘RAID10阵列&#…

Java 虚拟机中的内存结构

1 内存结构 1.1 程序计数器 1.1.1 定义 Program Counter Register 程序计数器(寄存器) 作用:是记住下一条 jvm 指令的执行地址 特点: 是线程私有的(每个线程独有自己的一份)不会存在内存溢出 1.1.2 作…

、写入Shellcode到注册表上线

其实本质就是将shellcode写入到注册表中,然后读取注册表中的shellcode,然后创建线程去执行shellcode。 如下图: 写入注册表shellcode 这里将shellcode写入到注册表中,在我们需要的时候再去读取然后执行。 这里用到如下两个Windows API函…

Zookeeper-应用实战

Zookeeper Java客户端实战 ZooKeeper应用的开发主要通过Java客户端API去连接和操作ZooKeeper集群。 ZooKeeper官方的Java客户端API。 第三方的Java客户端API,比如Curator。 ZooKeeper官方的客户端API提供了基本的操作:创建会话、创建节点、读取节点、更新数据、…

Leetcode—415.字符串相加【简单】

2023每日刷题(六十八) Leetcode—415.字符串相加 实现代码 class Solution { public:string addStrings(string num1, string num2) {string ans;int len1 num1.size();int len2 num2.size();int i len1 - 1, j len2 - 1;int sum 0, c 0;while(i…

面试题 01.01. 判定字符是否唯一(优质解法)

链接:面试题 01.01. 判定字符是否唯一 代码: class Solution {public boolean isUnique(String astr) {//s[i]仅包含小写字母,数据范围小于 32 位,我们可以使用 int 变量的比特位来代替数组// 每个小写字符对应 bitMap 中的一个比…

DETR 【目标检测里程碑的任务】

paper with code - DETR 标题 End-to-End Object Detection with Transformers end-to-end 意味着去掉了NMS的操作(生成很多的预测框,nms 去掉冗余的预测框)。因为有了NMS ,所以调参,训练都会多了一道工序&#xff0c…

小程序本地文件读、写、追加数据操作,以及修改文件内容

小程序系统文件管理器 FileSystemManager 要操作/读取本地文件,首先需要创建文件或文件夹,然后再对文件进行读写操作; 首先创建文件 FileSystemManager.writeFile 可直接创建文件并写入内容 定义文件路径,此路径在读写操作时保持一致 const path = `${wx.env.USER_DATA…

在Jetpack Compose中使用ExoPlayer实现直播流和音频均衡器

在Jetpack Compose中使用ExoPlayer实现直播流和音频均衡器 背景 ExoPlayer与Media3的能力结合,为Android应用程序播放多媒体内容提供了强大的解决方案。在本教程中,我们将介绍如何设置带有Media3的ExoPlayer来支持使用M3U8 URL进行直播流。此外&#x…

html网页编写语言

html是一门语言,所有的网页都是用html这门语言编写出来的。 HTML(HyperText Markup Language):超文本标记语言。 超文本:超越了文本的限制,比普通文本更强大。除了文字信息,还可以定义图片&…

Netty-1-编写网络应用程序的基本步骤

编写网络应用程序的基本步骤如下: 完成代码编写。复查代码。“临门一脚"。上线及反馈。 完成代码编写 编写网络应用程序的第一步是完成代码编写。 选择传输协议 对于普通的应用程序而言,经过需求分析、定义业务数据结构和实现业务逻辑之后,我…

研究论文 20231123-Genome Biology:零样本学习预测细基因表达顺式调控模式

Li, Yongge, et al. "CREaTor: zero-shot cis-regulatory pattern modeling with attention mechanisms." Genome Biology 24.1 (2023): 266. 2023年11月23日见刊 微信分享:Genome Biology | CREaTor: 零样本学习预测细胞类型特异的基因表达顺式调控模式…

算法与数据结构--哈夫曼树与哈夫曼编码

演示视频: 【1】数据结构——五分钟搞定哈夫曼树,会求WPL值,不会你打我_哔哩哔哩_bilibili 【2】哈夫曼树和哈夫曼编码_哔哩哔哩_bilibili 【3】哈夫曼树的构造的做题三步骤_哔哩哔哩_bilibili 求哈夫曼编码的步骤: 1.根据字符及…

HTML标签(下)

一、表格标签 1.1表格的主要作用 主要用于显示、展示数据 1.2表格的基本语法 <td>单元格中的文字</td> 如果是表头单元格的话&#xff0c;eg:姓名&#xff0c;年龄<th> 姓名</th>&#xff08;th是table head&#xff09;; 作用&#xff1a;表头会…

用Python处理PDF:拆分与合并PDF文档

PDF文档在信息共享和数据保存方面被广泛使用&#xff0c;处理PDF文档也成为常见需求。其中&#xff0c;合并和拆分PDF文档能够帮助我们更有效地管理PDF文档&#xff0c;使文档内容分布更合理。通过合并&#xff0c;可以将相关文档整合成一个文件&#xff0c;以便更好地组织和提…