FastAPI 数据校验入门:用 Pydantic 给接口加上“安检”
在前面完成的 FastAPI 学生接口中,我们已经能正常增删改查,但接口存在一个明显隐患:用户传什么,接口就收什么。
本文先用一个真实的反例暴露问题,然后脱离 FastAPI,单独用一个 Demo 演示 Pydantic 的类型校验、字段约束、自定义校验器和模型转字典能力,为下一步在 FastAPI 中接入数据校验打基础。
一、问题复现:非法数据也能“新增成功”
打开 Swagger 文档,找到新增学生的 POST 接口,点击 Try it out,故意填入一组明显不合法的数据:
name为空- 学号是一个汉字
- 性别不是“男/女”
- 生日不是日期格式
点击 Execute 执行后,返回码居然是 201,数据被成功添加。
这说明 FastAPI 当前对请求体“照单全收”。如果被恶意提交非法用户信息,数据质量将完全失控。作为 API 开发者,必须对用户填写的数据做验证——这正是 Pydantic 要解决的问题。
二、认识 Pydantic
Pydantic 是一个 Python 第三方包。安装 FastAPI 时会作为依赖被自动安装,无需单独安装。在终端执行:
pip list
可以查到当前安装的 Pydantic 版本为 2.12.5,属于 2.0 版本系列。2.0 版本使用 Rust 重构,效率比 1.0 版本提升约 10 倍。
Pydantic 并不绑定 FastAPI,可以独立使用。本文先单独演示它的用法,下一节再讲如何接入 FastAPI。
三、搭建独立 Demo
新建一个与项目无关的测试目录 Demo,在其中创建文件 PydanticDemo.py。这个文件只演示 Pydantic 本身,与 FastAPI 无关。
1. 定义基础模型
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
继承 BaseModel 后,类中声明的属性就带上了类型约束。使用方式与普通面向对象类类似:
u = User(name="Andy", age=18)
print(u.name)
print(u.age)
运行后正常输出 Andy 和 18。
2. 自动类型转换
把 age 的传参改成字符串 "18":
u = User(name="Andy", age="18")
print(u.age)
虽然编辑器标红提示类型不符,但运行依然正常输出。Pydantic 会把可转换的字符串自动转成整型。
3. 无法转换时报错
把 age 改成 "abc" 再运行,程序报错,提示 age 字段的输入必须是整型。这就是最基础的类型校验。
四、用 Field 增加字段约束
引入 Field 对字段做更细的约束。常用参数包括:
gt:大于ge:大于等于lt:小于le:小于等于min_length/max_length:最小/最大长度pattern:正则表达式
改造模型:
from pydantic import BaseModel, Field
class User(BaseModel):
name: str = Field(min_length=4, max_length=50)
age: int = Field(ge=1, le=99)
测试 1:age 超出上限
传入 age=100 运行,报错提示 age 的输入需要小于等于 99。
测试 2:合法数据通过
把 age 改为 80、name 改为 18 个字符的正常姓名,运行无任何问题。
测试 3:name 长度不足
把 name 改成三个字符运行,报错提示长度至少为 4。输入两个汉字“大雄”同样报错,因为字符数小于 4。
4. 可选字段与默认值
如果某个字段允许不传,可以声明为可选并给默认值:
age: int | None = None
不传 age 时运行,输出结果为 None。
五、用 field_validator 做自定义校验
Field 只能做通用约束。如果业务规则更复杂(比如姓名不能全是空格),需要用 field_validator 定义字段级校验方法。
from pydantic import BaseModel, Field, field_validator
class User(BaseModel):
name: str = Field(min_length=4, max_length=50)
age: int = Field(ge=1, le=99)
@field_validator("name")
def clean_name(cls, v: str) -> str:
v = v.strip()
if not v:
raise ValueError("姓名不能全为空格")
if len(v) < 4 or len(v) > 50:
raise ValueError("姓名长度在4到50个字符之间")
return v
要点说明:
- 方法名固定为
clean_<字段名>形式,第一个参数是cls,第二个参数v是待校验的字段值。 - 先
strip()去掉前后空格,再判断是否为空、长度是否合规。 - 必须
return v。如果不返回,字段值会变成None。
测试时传入不合规的姓名,报错信息显示 ValueError: 姓名长度在4到50个字符之间,说明自定义校验生效。
六、模型转字典
Pydantic 模型可以快速转成字典,方便后续序列化或入库:
u = User(name="大熊课堂", age=18)
print(u.model_dump())
运行后输出 {'name': '大熊课堂', 'age': 18},得到的是一个标准字典。
小结
一句话概括 Pydantic:系统类型 + 数据校验 + 数据解析 + 数据建模。它让 Python 从动态语言变成拥有强类型数据约束的编辑器,这也是 FastAPI 必须引入它的原因。
本文覆盖的能力清单:
| 能力 | 用法 |
|---|---|
| 基础类型校验 | 继承 BaseModel,声明 name: str、age: int |
| 自动类型转换 | 可转换的字符串自动转目标类型,不可转换则报错 |
| 字段约束 | Field(min_length=..., max_length=..., ge=..., le=...) |
| 可选字段 | Optional[int] = None |
| 自定义校验 | @field_validator("字段名") + clean_字段名 方法 |
| 模型转字典 | model_dump() |
下一节将把 Pydantic 接入 FastAPI,替换掉当前“照单全收”的请求体,让新增学生接口真正具备数据校验能力。
想系统学习这门课程?
你已阅读完本文。需要更完整的知识体系,可以继续了解「FastAPI 项目实战」。
查看课程详情