数据校验与 Pydantic
校验分三层理解
| 层次 | 例子 | 常见处理位置 |
|---|---|---|
| 结构与类型 | 年龄应是整数 | Pydantic、参数声明 |
| 字段与字段关系 | 结束时间晚于开始时间 | 模型校验器 |
| 业务与外部状态 | 用户名未被占用、库存充足 | 业务函数、数据库约束 |
“价格是正数”可以在字段规则里检查;“商品当前还有多少库存”往往要查询数据库。不要把所有业务判断都放进模型校验器。
常见约束
| 约束 | 含义 | 示例 |
|---|---|---|
gt | 大于 | gt=0 |
ge | 大于等于 | ge=0 |
lt | 小于 | lt=100 |
le | 小于等于 | le=100 |
min_length | 字符串或容器最短长度 | min_length=1 |
max_length | 字符串或容器最长长度 | max_length=100 |
pattern | 字符串正则规则 | pattern=r"^[A-Za-z0-9_]+$" |
在请求体字段中使用 Field();在查询参数中使用 Query();在路径参数中使用 Path()。规则相似,但参数所在的位置不同。官方字段校验说明、官方路径数值校验说明
完整示例:清理标题并拒绝空白
from fastapi import FastAPI
from pydantic import BaseModel, ConfigDict, Field, field_validator
app = FastAPI()
class ArticleCreate(BaseModel):
model_config = ConfigDict(extra="forbid")
title: str = Field(min_length=1, max_length=100)
content: str = Field(min_length=1)
@field_validator("title")
@classmethod
def validate_title(cls, value: str) -> str:
cleaned = value.strip()
if not cleaned:
raise ValueError("标题不能只有空格")
return cleaned
@app.post("/articles", status_code=201)
def create_article(article: ArticleCreate):
return article这里的 field_validator 默认在字段基础解析之后执行。value 是待检查的标题,返回值会成为模型中最终保存的标题。
extra="forbid" 表示客户端不能偷偷多传未定义的字段。Pydantic 模型默认通常会忽略多余字段;选择忽略还是拒绝,应按接口约定决定。Pydantic 模型说明、Pydantic 校验器说明
必填、默认值、空值
| 定义 | 能省略吗 | 能传 null 吗 |
|---|---|---|
name: str | 不能 | 不能 |
name: str = "未命名" | 能 | 不能 |
name: str | None | 不能 | 能 |
name: str | None = None | 能 | 能 |
这个表对 Pydantic 2 模型字段尤其重要。允许 None 只说明取值范围,不自动表示字段可省略。 Pydantic 必填与可空字段迁移说明
类型转换与严格模式
常见情况下,Pydantic 会尝试将合法的数字文本转换为数字,例如模型中的 count: int 可能接受 "3"。但它不会把任意不合法内容变成你想要的数据。
如果业务要求 JSON 中必须真的提供整数,可为对应字段使用严格类型,例如:
from pydantic import BaseModel, StrictInt
class CountInput(BaseModel):
count: StrictInt这个字段会拒绝字符串 "3"。查询参数天然来自文本,不宜不加判断地照搬 JSON 字段的严格策略。Pydantic 严格模式说明
Pydantic 2 常用方法
以下是独立语法示例:
from pydantic import BaseModel
class Note(BaseModel):
title: str
description: str | None = None
note = Note(title="学习计划")
print(note.model_dump())
print(note.model_dump_json())
print(note.model_dump(exclude_unset=True))
parsed = Note.model_validate({"title": "第二份计划"})| 方法 | 用途 |
|---|---|
model_dump() | 转为 Python 字典 |
model_dump(mode="json") | 输出适合 JSON 的数据类型 |
model_dump_json() | 转为 JSON 字符串 |
model_validate(data) | 解析并校验输入数据 |
model_dump(exclude_unset=True) | 仅保留客户端显式提供过的字段 |
exclude_unset=True 在 PATCH 中非常重要。它依据“有没有传过字段”,不是依据值是否为 None。
识别旧教程写法
| 常见旧写法 | 本手册采用的 Pydantic 2 写法 |
|---|---|
.dict() | .model_dump() |
.json() | .model_dump_json() |
.parse_obj() | .model_validate() |
orm_mode = True | ConfigDict(from_attributes=True) |
@validator | @field_validator |
从 pydantic 导入 BaseSettings | 从 pydantic_settings 导入 |
这张表是识别方向,不是完整的自动替换规则。校验器行为、配置方式等还有变化,迁移真实项目时应检查官方迁移说明。Pydantic 2 迁移指南
本章练习
定义注册模型:用户名 3~20 个字符,年龄 18~120,用户名只能使用字母、数字和下划线,拒绝额外字段。
过关标准:能区分类型错误、字段错误与业务错误,并解释省略字段和显式空值的区别。