Pydantic v2 中 BaseModel 默认不严格,需显式配置 strict=True 和 extra="forbid" 才实现真正严格校验:前者禁用类型自动转换,后者禁止额外字段;嵌套模型、API路由(如FastAPI)及错误处理均需逐层适配,否则校验失效。

Pydantic v2 里 BaseModel 默认不 strict,得手动开
Pydantic 默认允许传入额外字段、类型宽松转换(比如把字符串 "123" 自动转成 int),这在 API 入参校验时容易埋雷。要真正“严格”,必须显式启用 strict 模式——不是靠文档猜,而是靠两个关键配置:strict=True 和 extra="forbid"。
-
strict=True在字段定义里生效:比如user_id: int = Field(..., strict=True),此时传"123"会直接报Input should be a valid integer,不尝试转换 -
extra="forbid"写在model_config里:防止客户端多传字段,如请求带了未声明的debug_flag,立刻抛Unexpected keyword argument - v2 中
Config类已废弃,改用model_config = ConfigDict(extra="forbid")
嵌套模型 + strict 的坑:子模型也得自己标 strict
父模型设了 strict=True,不代表子模型自动继承。常见错误是只在顶层加 strict,结果嵌套的 address: Address 依然接受字符串转 dict 或忽略字段。
- 每个嵌套的
BaseModel子类都需独立声明model_config = ConfigDict(strict=True) - 字段级
strict=True优先级高于模型级,但仅对当前字段生效;模型级strict=True是对所有字段的默认行为(仍可被单个字段覆盖) - 示例:
class User(BaseModel): name: str = Field(..., strict=True); address: Address—— 这里address必须在Address类内部也配model_config,否则不严格
API 路由里怎么接?FastAPI 默认不 strict,得手动传 context
FastAPI 的 Body 或 Query 参数默认走 Pydantic 的宽松解析,即使你的模型写了 strict=True,也可能被绕过。原因在于 FastAPI 内部调用 .model_validate() 时没传 strict 上下文。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
- 正确做法:在路由函数参数里显式指定
body=Body(..., strict=True)(FastAPI 0.104+) - 或更可靠的方式:在模型的
__pydantic_core_schema__钩子里强制注入 strict,但太重;推荐用中间件拦截请求体后调用User.model_validate(json_data, strict=True) - 注意:
strict=True会禁用所有隐式类型转换,包括datetime字符串解析,必须确保前端传 ISO 格式,否则报Input should be a valid datetime
ValidationError 的 message 太泛?靠 loc 和 input 定位真实问题
严格模式下报错信息往往只说 Input should be a valid integer,但不知道是哪个字段、哪个嵌套层级出的问题。不能只看 msg,得挖 error.loc 和 error.input。
立即学习“Python免费学习笔记(深入)”;
-
error.loc返回元组,如("user", "id")或("items", 0, "price"),精准定位路径 -
error.input是原始传入值,比如"abc"或None,确认是不是前端传了空字符串或 null - 别依赖
str(exc)做日志,应遍历exc.errors()提取loc/input/msg组装结构化错误响应
strict 不是开关一按就完事,每个嵌套层、每次反序列化入口、每条错误路径都得单独确认——漏掉任意一处,校验就形同虚设。

















