

【个人主页:玄同765】
大语言模型(LLM)开发工程师|中国传媒大学·数字媒体技术(智能交互与游戏设计) 深耕领域:大语言模型开发 / RAG知识库 / AI Agent落地 / 模型微调 技术栈:Python / LangChain/RAG(Dify+Redis+Milvus)| SQL/NumPy | FastAPI+Docker ️ 工程能力:专注模型工程化部署、知识库构建与优化,擅长全流程解决方案 专栏传送门:LLM大模型开发 项目实战指南、Python 从真零基础到纯文本 LLM 全栈实战、从零学 SQL + 大模型应用落地、大模型开发小白专属:从 0 入门 Linux&Shell 「让AI交互更智能,让技术落地更高效」 欢迎技术探讨/项目合作! 关注我,解锁大模型与智能交互的无限可能!
你是不是写过大量 if-elif 验证接口参数的代码?比如判断用户名长度、邮箱格式、密码强度,漏一个就可能引发生产事故。这篇讲 FastAPI 内置的 Pydantic 库,只要用 Python 类型注解定义数据结构,它就能自动验证参数类型、范围、格式,还能生成详细的错误提示,让你少写 90% 的验证代码。
在 API 接口开发中,参数验证是绕不开的环节。如果你用 Flask 或 Django 默认模式,通常需要写大量的 if-elif 语句判断参数是否符合要求:
这些手动验证的代码不仅繁琐易错,而且维护成本高 —— 一旦业务规则发生变化,你需要逐一修改验证逻辑,稍不留神就会漏改导致生产事故。
直到 Pydantic 出现,这些问题被彻底解决。作为 FastAPI 的默认数据验证库,Pydantic 基于 Python 3.8+ 的类型注解实现数据验证,能自动验证接口的参数和返回值,不符合要求时会返回详细的错误信息,让你少写 90% 的验证代码。
Pydantic 的所有功能都围绕一个核心类 ——BaseModel。你可以通过继承 BaseModel 来定义数据结构,并在类中用类型注解和可选的验证字段配置参数验证规则。
打开上一篇创建的 main.py 文件,输入以下代码定义一个用户注册的数据结构:
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
# 定义用户注册的数据结构
class UserRegister(BaseModel):
username: str
email: EmailStr
password: str
age: int = None这段代码定义了一个 UserRegister 类,继承自 BaseModel,包含以下字段:
username:用户名,类型为字符串,必填(没有默认值);email:邮箱,类型为 EmailStr(Pydantic 内置的邮箱格式验证类型),必填;password:密码,类型为字符串,必填;age:年龄,类型为整数,可选(默认值为 None)。接下来,我们写一个用户注册的 POST 请求接口,并用 UserRegister 类验证请求体参数:
@app.post("/register")
def user_register(user: UserRegister):
"""
用户注册的接口
:param user: 用户注册信息(请求体参数,类型为 UserRegister)
:return: 注册成功的响应
"""
return {"message": "用户注册成功", "data": user}这段代码实现了一个路径为 /register 的 POST 请求接口,user 参数的类型是 UserRegister,FastAPI 会自动将请求体的 JSON 数据转换为 UserRegister 类的实例,并进行参数验证。
保存 main.py 文件,FastAPI 会自动热重载(如果启用了 --reload 参数)。接下来,我们通过 Swagger UI 文档测试接口的验证效果。
在浏览器中输入 http://127.0.0.1:8000/docs,点击 /register 接口旁边的 Try it out 按钮,分别测试以下几种场景:
在请求体中删除 email 字段,输入以下 JSON 数据:
{
"username": "testuser",
"password": "Test1234"
}点击 Execute 按钮,在下方的 Responses 区域会看到详细的错误信息:
{
"detail": [
{
"loc": [
"body",
"email"
],
"msg": "field required",
"type": "value_error.missing"
}
]
}将 age 字段的值设为字符串 abc,输入以下 JSON 数据:
{
"username": "testuser",
"email": "testuser@example.com",
"password": "Test1234",
"age": "abc"
}点击 Execute 按钮,在下方的 Responses 区域会看到详细的错误信息:
{
"detail": [
{
"loc": [
"body",
"age"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}将 email 字段的值设为无效格式的字符串 testuserexample.com,输入以下 JSON 数据:
{
"username": "testuser",
"email": "testuserexample.com",
"password": "Test1234",
"age": 18
}点击 Execute 按钮,在下方的 Responses 区域会看到详细的错误信息:
{
"detail": [
{
"loc": [
"body",
"email"
],
"msg": "value is not a valid email address",
"type": "value_error.email"
}
]
}除了内置的类型注解验证,Pydantic 还提供了丰富的高级验证功能,你可以通过字段配置参数或自定义验证函数实现更复杂的验证规则。
你可以通过 Field 函数(来自 pydantic 库)配置字段的验证规则,如长度范围、数值范围、正则表达式等。
打开 main.py 文件,修改 UserRegister 类:
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr, Field
import re
app = FastAPI()
class UserRegister(BaseModel):
# 用户名:长度在 3-20 个字符之间,只能包含字母、数字和下划线
username: str = Field(..., min_length=3, max_length=20, pattern=r"^[a-zA-Z0-9_]+$")
# 邮箱:必填,必须是有效的邮箱格式
email: EmailStr
# 密码:长度在 8-20 个字符之间,必须包含至少一个大写字母、一个小写字母和一个数字
password: str = Field(..., min_length=8, max_length=20,
regex=r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).*$")
# 年龄:可选,必须在 1-120 岁之间
age: int = Field(None, ge=1, le=120)其中:
... 表示必填字段(等同于没有默认值);min_length 和 max_length 配置字符串字段的长度范围;pattern 或 regex 配置字符串字段的正则表达式;ge 和 le 配置数值字段的范围(ge 表示大于等于,le 表示小于等于)。如果字段配置参数无法满足你的验证需求,你可以通过 @validator 装饰器(来自 pydantic 库)自定义验证函数。
比如,我们要验证密码不能包含用户名,修改 UserRegister 类:
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr, Field, validator
import re
app = FastAPI()
class UserRegister(BaseModel):
username: str = Field(..., min_length=3, max_length=20, pattern=r"^[a-zA-Z0-9_]+$")
email: EmailStr
password: str = Field(..., min_length=8, max_length=20,
regex=r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).*$")
age: int = Field(None, ge=1, le=120)
# 自定义验证函数,验证密码不能包含用户名
@validator("password")
def password_not_contain_username(cls, v, values):
"""
验证密码不能包含用户名的自定义函数
:param cls: 类本身(Pydantic 验证时会自动传递)
:param v: 密码字段的值
:param values: 其他已验证的字段值(如果有)
:return: 验证通过的密码值
:raises ValueError: 验证失败时抛出的异常
"""
if "username" in values and v.lower().find(values["username"].lower()) != -1:
raise ValueError("密码不能包含用户名")
return v其中:
@validator("password") 装饰器表示该函数用于验证 password 字段;values 参数包含了其他已验证的字段值,这里我们用它来获取用户名;ValueError 异常,FastAPI 会自动将其转换为 HTTP 422 错误响应。除了验证接口参数,Pydantic 还可以验证接口的返回值,确保接口返回的数据符合预期的格式和类型。
打开 main.py 文件,定义一个用户信息的数据结构:
# 定义用户信息的数据结构
class UserInfo(BaseModel):
user_id: int
username: str
email: EmailStr
age: int = None
create_time: str
# 修改用户注册接口的返回值类型
@app.post("/register", response_model=UserInfo)
def user_register(user: UserRegister):
"""
用户注册的接口
:param user: 用户注册信息(请求体参数,类型为 UserRegister)
:return: 注册成功的响应(类型为 UserInfo)
"""
# 模拟生成用户 ID 和创建时间
user_id = 123
create_time = "2025-01-01 10:00:00"
# 构造返回值
return {
"user_id": user_id,
"username": user.username,
"email": user.email,
"age": user.age,
"create_time": create_time,
# 额外的字段(不会返回给前端)
"password": user.password
}其中:
response_model=UserInfo 装饰器参数表示接口的返回值类型必须是 UserInfo 类的实例;UserInfo 类中没有定义的字段(如 password),FastAPI 会自动将其过滤掉,不会返回给前端;UserInfo 类中定义的必填字段(如 user_id),或字段类型不符合要求,FastAPI 会返回详细的错误信息。Pydantic 提供了丰富的常用类型注解,覆盖了 API 接口开发中常见的数据类型:
类型注解 | 功能 | 示例 |
|---|---|---|
str | 字符串类型 | username: str |
int | 整数类型 | age: int |
float | 浮点数类型 | score: float |
bool | 布尔类型 | is_active: bool |
EmailStr | 邮箱格式验证类型 | email: EmailStr |
UrlStr | URL 格式验证类型 | website: UrlStr |
List[T] | 列表类型,元素类型为 T | tags: List[str] |
Dict[K, V] | 字典类型,键类型为 K,值类型为 V | user_profile: Dict[str, str] |
Union[T1, T2] | 联合类型,值可以是 T1 或 T2 | avatar: Union[str, bytes] |
Optional[T] | 可选类型,值可以是 T 或 None | description: Optional[str] |
datetime | 日期时间类型 | create_time: datetime |
如果你已经掌握了 Pydantic 的基础和高级验证功能,下一步你可以学习以下内容:
BaseModel 类,验证复杂的 JSON 数据结构;parse_obj、parse_raw、parse_file 方法转换不同格式的数据;dict、json 方法将数据序列化为字典或 JSON 字符串;Pydantic 作为 FastAPI 的默认数据验证库,基于 Python 类型注解实现数据验证,能自动验证接口的参数和返回值,不符合要求时会返回详细的错误信息,让你少写 90% 的验证代码。
它的简单高效、丰富的高级验证功能、与 FastAPI 的完美集成,让参数验证不再是一个头疼的环节,而是一个愉快的过程。如果你之前一直用手动验证的方法,不妨尝试一下 Pydantic,相信它会给你带来不一样的体验。