一、ValidationError 异常优先级
序列化器验证顺序
第一级:字段内置验证
- 序列化器先进行字段内置验证,像
min_length、required这类。一旦验证不通过,就会立即抛出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从入门到实战》专栏!关注不迷路~