Pydantic v2 验证失败默认抛 ValidationError,但 FastAPI 会转为 422 响应;需用 model_validate 替代 parse_obj,捕获 RequestValidationError(FastAPI)或 ValidationError(手动),e.errors() 提供结构化错误定位;field_validator 用于单字段校验,model_validator(mode='after') 用于跨字段逻辑;验证不可关闭,应限于入口层,且校验函数须为纯计算。

Pydantic v2 模型验证失败时默认不抛异常?
不是不抛,是 model_validate 和 model_validate_json 默认严格校验,但如果你用的是 BaseModel.parse_obj(v1 风格)或没显式 catch,错误可能被吞掉——尤其在 FastAPI 里,它会把验证失败转成 422 响应,看起来像“没报错”。
- 用
model_validate替代已弃用的parse_obj,它是 v2 官方推荐入口 - 手动验证时加
try/except pydantic.ValidationError as e:,别依赖日志静默失败 - FastAPI 中验证失败会进
RequestValidationError,不是ValidationError,捕获时别写错类型
字段缺失、类型错、值越界——报错信息怎么快速定位问题?
Pydantic 默认报错是结构化字典,直接 print 不友好;而且同一字段多个错误(比如既为空又超长)只显示第一个,容易漏判。
- 用
e.errors()拿到完整错误列表,每个元素含loc(路径)、msg、type,例如[{'loc': ('user', 'age'), 'msg': 'Input should be greater than 0', 'type': 'greater_than'}] -
loc是 tuple,嵌套模型会是('items', 0, 'name'),别当成字符串解析 - 调试时可临时加
print(json.dumps(e.errors(), indent=2)),比 str(e) 清晰十倍
自定义验证逻辑:field_validator 和 model_validator 怎么选?
二者触发时机和上下文不同,混用容易导致重复校验或访问不到字段。
-
@field_validator('email')只收单个字段值,适合格式检查(如正则、非空),不能访问其他字段 -
@model_validator(mode='after')拿到整个实例,适合跨字段逻辑(如end_time > start_time),但注意此时字段可能还是原始类型,未经过类型转换 - 如果需要在类型转换后校验多字段,用
mode='after';若只是清洗单字段(如去掉空格),用before=True的field_validator
性能敏感场景下,验证要不要关?
验证本身有开销,尤其嵌套深、字段多时;但关掉 ≠ 安全,而是得换方式兜底。
立即学习“Python免费学习笔记(深入)”;
- Pydantic 不提供全局“跳过验证”开关,强行绕过要用
__pydantic_core_schema__黑魔法,不推荐 - 高频内部服务且数据可信,可用
RootModel或纯 dict 处理,验证改由上游或 schema 文档约束 - 更稳妥的做法:验证只在 API 入口做,内部函数接收已验证模型,类型注解 + mypy 保后续逻辑安全
最常被忽略的一点:field_validator 里做 HTTP 请求或数据库查询,会让验证变成 IO 瓶颈——验证函数必须是纯计算,否则模型初始化就卡住。










