Pydantic v2 中 BaseModel 必须显式使用 Field() 声明字段约束(如 ...、min_length 等)才能真正校验;仅靠类型注解或默认值无法触发运行时校验,需配合单元测试验证 ValidationError。

Pydantic v2 里 BaseModel 怎么写才能真正校验字段?
不加 Field 或类型注解,BaseModel 只做类型转换,不报错也不拦截非法值。比如 age: int 遇到 "abc" 会直接抛 ValidationError,但 age: int = None 就可能绕过校验——因为默认值让字段变成可选,且没约束逻辑。
- 必须显式用
Field控制必填/默认/校验:比如email: str = Field(..., min_length=5),...表示必填 - 字符串长度、数字范围、正则匹配等约束,都得靠
Field的参数,不是类型本身能管的 - 别依赖 IDE 提示判断是否校验生效——运行时才会触发,建议配个单元测试跑
model_validate传坏数据看报错
为什么 model_validate 报错信息看不懂?怎么快速定位字段?
默认错误堆栈里字段路径是嵌套的,比如 value_error.missing 或 string_too_short,但没直接告诉你哪个字段出问题。尤其在嵌套模型或列表里,光看 loc 元组(如 ['user', 'profile', 0, 'name'])容易懵。
- 用
exc.errors(include_url=False)提取结构化错误,每个项含loc、msg、type,比原始异常好解析 - 前端传参字段名和模型字段不一致时,别硬改模型名,用
alias:比如user_name: str = Field(alias="username"),否则loc显示的是别名,调试时对不上 - 批量校验多个对象?别一个个 try/catch,用
validate_python+from_attributes=True配合 ORM 对象,但注意 Pydantic v2 默认不自动转换属性名
表单提交空字符串 or null 怎么统一转成 None 或报错?
Web 表单常把空输入发成 "" 或 null,而 Python 层面 str 类型字段默认不接受空串,Optional[str] 又会让空串被当成合法值存进去——这不是校验,是放行。
- 用
Field(default=None, validate_default=True)配合自定义@field_validator,在值为""或None时主动 raise - 更省事:全局配置
model_config = ConfigDict(strict=False, coerce_numbers_to_str=False),但别开coerce_numbers_to_str,否则"123"会被静默转成int - 前后端约定空字段传
undefined?那得在 FastAPI 里用Body(..., embed=True)配合ExcludeUnset,不然 Pydantic 会把缺失字段当默认值处理
FastAPI 里用 Body 接参,为什么字段校验没生效?
常见现象:模型定义了 min_length=3,但 POST 一个空字符串过去,接口没报错,还进了业务逻辑。根本原因是 FastAPI 默认用 model_validate_json,而 JSON 解析后空字符串就是 "",它符合 str 类型,校验只在模型初始化时走——但如果你在路由函数里手动调了 MyModel(**data),就绕过了 FastAPI 的校验链。
立即学习“Python免费学习笔记(深入)”;
- 必须让 FastAPI 自己实例化模型:参数写成
def endpoint(data: MyModel),别自己 new - 如果用了
Form而非Body,字段会变成str或UploadFile,得额外用Depends包一层验证函数 - 自定义
@field_validator里别 print 或 log,FastAPI 捕获异常后不会输出你写的日志,调试时容易以为没进 validator
字段级校验看似简单,但空值、别名、嵌套、框架集成这四点,任何一个没对齐,就会让校验形同虚设。最稳妥的做法是:每个字段都显式声明 Field,每次改模型都重跑一遍边界值测试。










