一、ValidationError 异常优先级

序列化器验证顺序

第一级:字段内置验证

  • 序列化器先进行字段内置验证,像 min_lengthrequired这类。一旦验证不通过,就会立即抛出 ValidationError,并且后续的验证步骤不会再执行。
    username = serializers.CharField(
min_length=settings.USERNAME_MIN_LENGTH,
max_length=settings.USERNAME_MAX_LENGTH,
error_messages={
"required": "登录账号不能为空",
"min_length": f"账号长度至少为{settings.USERNAME_MIN_LENGTH}位",
"max_length": f"账号长度不能超过{settings.USERNAME_MAX_LENGTH}位",
},
)

第二级:自定义字段验证方法

  • 若定义了类似 validate_<field_name> 这样的自定义验证方法,它会在字段内置验证之后执行。要是验证失败,同样会抛出 ValidationError
    def validate_username(self, value):
if not re.match(r"^[A-Za-z0-9]+$", value):
raise serializers.ValidationError("账号格式为数字以及字母")
return value

第三级:对象级验证

  • validate() 方法会在所有字段验证都通过之后执行,用于对多个字段进行联合验证。
    def validate(self, data):
if data["password"] != data["confirm_password"]:
raise serializers.ValidationError(
{"confirm_password": "两次输入的密码不一致"}
)
return data

第四级:数据库验证

进行反序列化操作时,序列化器验证通过后,会写入数据库。如果写入失败,会抛出异常。例如:

  • 唯一性约束冲突:当模型字段被设置为 unique=True 时,如果插入重复数据,就会触发该异常。
  • 外键约束失败:关联一个不存在的外键对象时,会引发此异常。
  • NOT NULL 约束失败:当模型中设置为 null=False 的字段没有值时,会出现该异常。

参考资料:

自动生成验证器

自动生成验证器示例

  • 模型字段定义中,指定了unique=True参数
username = models.CharField(
max_length=30, unique=True, db_comment="用户账号", help_text="用户账号"
)

  • 定义序列化器,继承了ModelSerializer
# 在下面序列化器,只定义了unique 错误信息,并没有显式声明 unique=True
class UserImportSerializer(serializers.ModelSerializer):
class Meta:
model = SystemUsers
fields = [
"username",
]
extra_kwargs = {
"username": {
"min_length": settings.USERNAME_MIN_LENGTH,
"max_length": settings.USERNAME_MAX_LENGTH,
"error_messages": {
"min_length": "用户账号长度不能少于4个字符",
"max_length": "用户账号长度不能超过30个字符",
"unique": "用户账号已经存在",
},
},
}
  • 进入django shell,查看最终生成的序列化器。可以看到自动添加了UniqueValidator验证器
# 进入 django shell
python manage.py shell # 查看最终生成的序列化器
>>> from myapp_system.user.serializers import UserImportSerializer
>>> ser=UserImportSerializer()
>>> print(ser) ### 输出结果
username = CharField(error_messages={'min_length': '用户账号长度不能少于4个字符', 'max_length': '用户账号长度不能超过30个字符', 'unique': '用户账号已经存在'}, help_text='用户账号', max_length=30, min_length=4, validators=[<UniqueValidator(queryset=SystemUsers.objects.all())>])

注意:

  • 此时的'unique': '用户账号已经存在'错误提示,并不会生效,因为被内置验证器覆盖了。
  • 内置验证器默认返回的错误信息提示是:具有 username 的 system users 已存在。

二、实战

实战场景

取消自动生成验证器,实现自定义异常信息提示。

实战原理

ValidationError异常信息提示,与下面因素相关

  • 序列化器验证顺序:在哪个阶段抛出ValidationError异常,则返回相应阶段的异常信息提示
  • 序列化器的定义:如果序列化器继承了ModelSerializer,默认会为字段自动生成验证器

实战步骤

在定义序列化器时,设置:

  • 取消字段自动生成的验证器。
  • 添加字段自定义验证方法。例如示例代码中的validate_username()

实战效果

此时的异常提示信息为:用户账号 x 已经存在

点击查看完成代码


您正在阅读的是《Django从入门到实战》专栏!关注不迷路~

Django+DRF 实战:序列化器 ValidationError 触发机制完整指南的更多相关文章

  1. Django 学习之Django Rest Framework_序列化器_Serializer

    作用: 1.序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串. 2.反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型. 3 ...

  2. drf之序列化器的使用

    一.序列化器-Serializer 作用: 1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串 2. 完成数据校验功能 3. 反序列化,把客户端发送过来的数据,经 ...

  3. drf的序列化器

    三流 import sys #标准输出流 sys.stdout.write('123\n') sys.stdout.write('456\n') #标准输入流 res=sys.stdin.readli ...

  4. 066.Python框架DRF之序列化器Serializer

    一 序列化器-Serializer 作用: 1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串 2. 反序列化,把客户端发送过来的数据,经过request以后变成 ...

  5. DRF的序列化器Serializer

    一 序列化器的作用 1. 序列化,序列化器会把模型对象转换成字典,经过视图中response对象以后变成json字符串 2. 反序列化,视图中request会把客户端发送过来的数据转换成字典,序列化器 ...

  6. DRF中序列化器定义及使用

    首先需要明白序列化和反序列化的定义及作用: 序列化是将程序语言转换为JSON/XML; 反序列化是将JSON/XML转换为程序语言; 对应到Django中,序列化即把模型对象转换为字典形式, 在返回给 ...

  7. Django REST Framework序列化器

    Django序列化和json模块的序列化 从数据库中取出数据后,虽然不能直接将queryset和model对象以及datetime类型序列化,但都可以将其转化成可以序列化的类型,再序列化. 功能需求都 ...

  8. Django:RestFramework之-------序列化器

    8.序列化 功能: 对请求数据进行验证 对Queryset进行序列化 8.1一个简单序列化: import json from api import models from rest_framewor ...

  9. Django drf:序列化增删改查、局部与全局钩子源码流程、认证源码分析、执行流程

    一.序列化类的增.删.改.查 用drf的序列化组件   -定义一个类继承class BookSerializer(serializers.Serializer):   -写字段,如果不指定source ...

  10. 【Django drf】 序列化类常用字段类和字段参数 定制序列化字段的两种方式 关系表外键字段的反序列化保存 序列化类继承ModelSerializer 反序列化数据校验源码分析

    目录 序列化类常用字段类和字段参数 常用字段类 常用字段参数 选项参数 通用参数 序列化类高级用法之source source填写类中字段 source填写模型类中方法 source支持跨表查询 定制 ...

随机推荐

  1. FireDAC 下的批量 SQL 命令执行

    一.{逐条插入} procedure TForm1.Button1Click(Sender: TObject); const strInsert = 'INSERT INTO MyTable(Name ...

  2. Java 与 LLM 大模型融合的技术革命:JBoltAI 如何重构企业级 AI 开发范式

    Java 与 LLM 大模型融合的技术革命:JBoltAI 如何重构企业级 AI 开发范式 一.Java 技术栈的智能化转型挑战 随着 LLM(大语言模型)技术的突破,全球超过 900 万家 Java ...

  3. symfony学习笔记3.4(bundle、service、doctrine的使用…)

    yii.laravel框架都是基于symfony组件衍生,symfony的强大不用多说.文档里有的,很好找的就不写了 附: symfony官网  https://symfony.com/doc/3.4 ...

  4. k8s-1.18.0版本-kubeadmin部署(提供阿里云镜像)(二)master节点

    k8s-1.18.0版本-kubeadmin部署 (提供阿里云镜像) 个人服务器地址:http://101.201.140.7/wp-blog/ 系统开启kube-proxy的ipvs前置条件 从k8 ...

  5. Linux TCP网关的线程结构方案

    如果所示: 无论客户端还是服务端链接网关的socket都拆分为读EPoll.写EPoll分别独立. 有两个线程:线程A(左).线程B(右): 线程A负责服务端Socket的读和客户端socket的写, ...

  6. XXL-MQ v1.3.0 | 分布式消息队列

    Release Notes 1.[增强]消费者分组属性 "group" 支持为空,为空时自动赋值UUID,方便实现多分组广播消费: 2.[增强]海量数据堆积:消息数据存储在DB中, ...

  7. 遇到的问题之“input的值感觉没有设置上去,却有值”

    案例一.批量设置参数 1.被设置的框 改为下拉框的问题可参考:https://www.cnblogs.com/saoge/p/16985318.html <td> <app:inpu ...

  8. K-means 基本流程 Demo

    也是单纯搬个砖, 记个笔记, K-Means 最近是有在用的, 当然之前也有用的, 也是掉包来弄的, 已经很少会去自己写了, 这里的目的, 也是为了自己, 后面再遇到可以复制粘贴. 对, 情况就是这样 ...

  9. 操作系统 -- linux初始化(上):GRUB与vmlinuz的结构

    本节树立启动的整体流程,重点解读Linux上GRUB是怎样启动,以及内核里的"实权人物"-- vmlinuz内核文件是如何产生和运转的. 全局流程 在机器加电后,BIOS会进行自检 ...

  10. AMQP 和 JMS的区别

    MQ是消息通信的模型:实现MQ的大致有两种主流方式:AMQP.JMS. 1.2.1. AMQP AMQP是一种协议,更准确的说是一种binary wire-level protocol(链接协议).这 ...