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

news2025/6/19 3:14:20

文章目录

  • 一、反序列化数据校验源码分析
  • 二、断言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默认内置的配置

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动物分类识别教程+分类释义+界面展示

1.项目简介 动物分类教程分类释义界面展示 动物分类是生物学中的一个基础知识,它是对动物进行分类、命名和描述的科学方法。本教程将向您介绍动物分类的基本原则和方法,并提供一些常见的动物分类释义。 动物分类的基本原则 动物分类根据动物的形态、…

redis主从复制(在虚拟机centos的docker下)

1.安装docker Docker安装(CentOS)简单使用-CSDN博客 2.编辑3个redis配置 cd /etc mkdir redis-ms cd redis-ms/ vim redis6379.conf vim redis6380.conf vim redis6381.conf# master #端口号 port 6379#设置客户端连接后进行任何其他指定前需要使用的密码 requirepass 12345…

【SpringBoot篇】解决缓存击穿问题① — 基于互斥锁方式

文章目录 🌹什么是缓存击穿🌺基于互斥锁解决问题🛸思路 🏳️‍🌈代码实现 🌹什么是缓存击穿 缓存击穿是指在使用缓存系统时,对一个热点数据的高并发请求导致缓存失效,多个请求同时访…

ESP8266网络相框采用TFT_eSPI库TJpg_Decoder库mixly库UDP库实现图片传送

使用ESP8266和TFT_ESPI模块来显示图片数据。具体来说,我们将使用ILI9431显示器作为显示设备,并通过UDP协议将图片数据从发送端传输到ESP8266。最后,我们将解析这些数据并在TFT屏幕上显示出来。在这个过程中,我们将面临一些编程挑战…

The Cherno C++笔记 03

目录 Part 07 How the C Linker Works 1.链接 2.编译链接过程中出现的错误 2.1 缺少入口函数 注意:如何区分编译错误还是链接错误 注意:入口点可以自己设置 2.2 找不到自定义函数 2.2.1缺少声明 2.2.2自定义函数与引用函数不一致 2.3 在头文件中放入定义 …

conda环境下更改虚拟环境安装路径

1 引言 在Anaconda中如果没有指定路径,虚拟环境会默认安装在anaconda所安装的目录下,但如果默认环境的磁盘空间不足,无法满足大量安装虚拟环境的需求,此时我们需要更改虚拟环境的安装路径,有以下两种方案: 方案1: 每次…

【贪心算法】之 摆动序列(中等题)

实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度) 这就是贪心所贪的地方,让峰…

Java设计模式之单例模式以及如何防止通过反射破坏单例模式

单例模式 单例模式使用场景 ​ 什么是单例模式?保障一个类只能有一个对象(实例)的代码开发模式就叫单例模式 ​ 什么时候使用? 工具类!(一种做法,所有的方法都是static,还有一种单…

Python命令行参数解析:原理、技巧与实践

文章目录 引言命令行参数解析原理命令行参数概述使用argparse模块解析命令行参数1. 创建ArgumentParser对象2. 添加命令行参数3. 解析命令行参数4. 可选参数action5. 参数的类型转换 实践示例总结结束语 引言 在Python中,命令行参数解析是一个重要的主题&#xff0…

【稳定检索|投稿优惠】2024年绿色能源与电网电力系统国际会议(ICGEGPS 2024)

2024年绿色能源与电网电力系统国际会议(ICGEGPS 2024) 2024 International Conference on Green Energy and Grid Power Systems(ICGEGPS) 一、【会议简介】 2024年绿色能源与电网电力系统国际会议(ICGEGPS 2024)将在宜宾盛大召开。本次会议将聚焦绿色能源与电网电力系统的最新…

Linux——缓冲区

我在上篇博客留下了一个问题,那个问题就是关于缓冲区的问题,我们发现 文件有缓冲区,语言有用户级缓冲区,那么缓冲区到底是什么?,或者该怎 么认识缓冲区?这篇文章或许会让你有所认识,…

单例模式的基本用法

单例模式是众多设计模式中的一种,那说到设计模式,我们要想知道什么是设计模式? 设计模式就是一套反复使用、多数人知晓的、经过分类、代码设计经验总结。 使用设计模式是为了可重用代码、让代码更容易被他人理解,保证代码的可靠性。毫无疑问…

Oracle WebLogic Server WebLogic WLS组件远程命令执行漏洞 CVE-2017-10271

Oracle WebLogic Server WebLogic WLS组件远程命令执行漏洞 CVE-2017-10271 已亲自复现 漏洞名称漏洞描述影响版本 漏洞复现环境搭建漏洞利用 修复建议 漏洞名称 漏洞描述 在Oracle WebLogic Server 10.3.6.0.0/12.1.3.0.3/2.2.1/1.10/12.2.1.1/22.0(Application …

Pipelined-ADC设计二——结构指标及非理想因素(Part1)

本章将详细介绍电路各个模块的设计思路和设计中需要注意的关键点,给出流水线ADC中的非理想因素,并计算出流水线ADC各个模块具体指标。根据电路中信号的传输方向,依次介绍采样保持电路、Sub_ADC,MDAC 等模块的设计。(本…

【GitHub精选项目】短信系统测试工具:SMSBoom 操作指南

前言 本文为大家带来的是 OpenEthan 开发的 SMSBoom 项目 —— 一种用于短信服务测试的工具。这个工具能够发送大量短信,通常用于测试短信服务的稳定性和处理能力。在合法和道德的范畴内,SMSBoom 可以作为一种有效的测试工具,帮助开发者和系统…

关于redis单线程和IO多路复用的理解

首先,Redis是一个高性能的分布式缓存中间件。其复杂性不言而喻,对于Redis整体而言肯定不是只有一个线程。 我们常说的Redis 是单线程,主要是指 Redis 在网络 IO和键值对读写是采用一个线程来完成的,这也是 Redis 对外提供键值存储…

【ARMv8M Cortex-M33 系列 1 -- SAU 介绍】

文章目录 Cortex-M33 SAU 介绍SAU 的主要功能包括SAU 寄存器配置示例 Cortex-M33 SAU 介绍 在 ARMv8-M 架构中,SAU(Security Attribution Unit)是安全属性单元,用于配置和管理内存区域的安全属性。SAU 是 ARM TrustZone 技术的一…

论文阅读——Flamingo

Flamingo: a Visual Language Model for Few-Shot Learning 模型建模了给定交织的图片或支视频的条件下文本y的最大似然: 1 Visual processing and the Perceiver Resampler Vision Encoder:from pixels to features。 预训练并且冻结的NFNet&#xff…

kindeditor The method toJSONString() is undefined for the type JSONObject

kindeditor 插件上传文件出错的 json_simple-1.1.jar 也不知道是多老的项目,多老的包了,稀有东西

助力智能人群检测计数,基于DETR(DEtectionTRansformer)开发构建通用场景下人群检测计数识别系统

在一些人流量比较大的场合,或者是一些特殊时刻、时段、节假日等特殊时期下,密切关注当前系统所承载的人流量是十分必要的,对于超出系统负荷容量的情况做到及时预警对于管理团队来说是保障人员安全的重要手段,本文的主要目的是想要…