Django+DRF 实战:序列化器 ValidationError 触发机制完整指南

一、ValidationError 异常优先级

序列化器验证顺序

第一级:字段内置验证

  • 序列化器先进行字段内置验证,像 min_lengthrequired这类。一旦验证不通过,就会立即抛出 ValidationError,并且后续的验证步骤不会再执行。
ini 复制代码
    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
python 复制代码
    def validate_username(self, value):
        if not re.match(r"^[A-Za-z0-9]+$", value):
            raise serializers.ValidationError("账号格式为数字以及字母")
        return value

第三级:对象级验证

  • validate() 方法会在所有字段验证都通过之后执行,用于对多个字段进行联合验证。
kotlin 复制代码
    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参数
ini 复制代码
username = models.CharField(
        max_length=30, unique=True, db_comment="用户账号", help_text="用户账号"
)
  • 定义序列化器,继承了ModelSerializer
kotlin 复制代码
# 在下面序列化器,只定义了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验证器
python 复制代码
# 进入 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从入门到实战》专栏!关注不迷路~

相关推荐
LaughingZhu5 小时前
Product Hunt 每日热榜 | 2026-05-21
前端·人工智能·经验分享·chatgpt·html
怕浪猫5 小时前
Electron 开发实战(一):从零入门核心基础与环境搭建
前端·electron·ai编程
小鹏linux6 小时前
Ubuntu 22.04 部署开源免费具有精美现代web页面的Casdoor账号管理系统
linux·前端·ubuntu·开源·堡垒机
前端若水7 小时前
会话管理:创建、切换、删除对话历史
前端·人工智能·python·react.js
Bigger7 小时前
mini-cc:一个轻量级 AI 编程助手的诞生
前端·ai编程·claude
涵涵(互关)7 小时前
Naive-ui树型选择器只显示根节点
前端·ui·vue
BY组态7 小时前
Ricon组态系统最佳实践:从零开始构建物联网监控平台
前端·物联网·iot·web组态·组态
BY组态7 小时前
Ricon组态系统vs传统组态软件:为什么选择新一代Web组态平台
前端·物联网·iot·web组态·组态
SoaringHeart7 小时前
Flutter进阶:OverlayEntry 插入图层管理器 NOverlayZIndexManager
前端·flutter
放下华子我只抽RuiKe57 小时前
React 从入门到生产(四):自定义 Hook
前端·javascript·人工智能·深度学习·react.js·自然语言处理·前端框架