Pydantic中某字段校验失败时如何跳过其余字段的验证?
Pydantic 核心字段校验失败终止后续流程的原生实现方案
Pydantic v2(推荐升级)
v2版本原生提供了校验终止的配置项,直接在模型配置中指定validation_stop为FIRST_ERROR即可实现第一个错误出现后直接终止所有后续校验,不会触发后续校验逻辑,同时错误定位正常指向具体出错字段。
from pydantic import BaseModel, field_validator, ValidationStop from myapp import User from typing import Any class ChangePasswordRequest(BaseModel): model_config = { "arbitrary_types_allowed": True, # 第一个校验错误出现就终止全部后续校验流程 "validation_stop": ValidationStop.FIRST_ERROR } # 核心字段放在最前优先校验 user: User current_password: str new_password: str @field_validator("user") def user_is_active(cls, user: User): if user.inactive: raise ValueError("User is not active.") return user @field_validator("current_password") def current_password_validator(cls, password: str, values: dict[str, Any]): user: User = values["user"] if not user.check_password(password): raise ValueError("current_password is not valid.") return password
Pydantic v1 兼容方案
v1没有全局终止校验的原生配置,但可以通过以下两种方式实现需求,无需为每个校验器额外加判断逻辑:
方案1:主动抛出指定定位的ValidationError
Pydantic v1的字段校验按定义顺序执行,核心字段放在最前面定义,校验失败时主动抛出带字段定位的ValidationError,会直接终止整个校验流程:
from pydantic import BaseModel, validator, ValidationError from myapp import User class ChangePasswordRequest(BaseModel): class Config: arbitrary_types_allowed = True # 核心字段优先定义 user: User current_password: constr(min_length=1, max_length=255) new_password: constr(min_length=8, max_length=64) @validator("user") def user_is_active(cls, user: User): if user.inactive: raise ValidationError( errors=[{ "loc": ["user"], "msg": "User is not active.", "type": "value_error" }], model=cls ) return user @validator("current_password") def current_password_validator(cls, password: str, values: dict): user: User = values["user"] if not user.check_password(password): raise ValueError("current_password is not valid.") return password
方案2:root_validator 自定义错误定位
如果用root_validator的方案,只需主动构造错误信息指定loc字段,即可解决错误指向__root__的问题:
from pydantic import BaseModel, root_validator, ValidationError from myapp import User class ChangePasswordRequest(BaseModel): class Config: arbitrary_types_allowed = True user: User current_password: constr(min_length=1, max_length=255) new_password: constr(min_length=8, max_length=64) @root_validator(pre=True) def check_user_status(cls, values): user = values.get("user") if not user or user.inactive: raise ValidationError( errors=[{ "loc": ["user"], "msg": "User is not active.", "type": "value_error" }], model=cls ) return values
注意:不要使用
assert编写校验逻辑,Python运行时开启优化模式(添加-O参数)时,所有assert语句会被全局移除,导致校验逻辑失效。
内容的提问来源于stack exchange,提问作者umat
相关产品推荐
相关产品推荐

