Pydantic 与数据校验
Pydantic 是 FastAPI 的数据层,也是 Python 数据建模的事实标准。面试主线:模型怎么定义、嵌套怎么处理、校验失败长什么样、怎么序列化。
模型定义与约束
from pydantic import BaseModel, Field, EmailStr
class UserCreate(BaseModel):
name: str = Field(min_length=1, max_length=50)
age: int = Field(ge=0, le=150)
email: EmailStr
tags: list[str] = Field(default_factory=list)- 类型注解即校验规则:类型错误、范围越界自动拦截
Field约束:长度、范围、正则(pattern)、默认值- 内置类型:
EmailStr、HttpUrl、UUID、datetime(自动解析 ISO 格式) - 请求非法数据返回 422 校验错误(不是 400),响应体带字段级错误明细
嵌套模型
class Address(BaseModel):
city: str
zip_code: str
class Order(BaseModel):
id: int
user: UserCreate # 嵌套模型
items: list[Item] # 模型列表
metadata: dict[str, str] # 泛型容器嵌套自动递归校验:一层非法,整棵模型树报错。list[Model]、dict[str, Model] 直接声明,无需手写解析。
校验器
from pydantic import field_validator, model_validator
class Booking(BaseModel):
start: datetime
end: datetime
@field_validator("end")
@classmethod
def end_after_start(cls, v, info):
if info.data.get("start") and v <= info.data["start"]:
raise ValueError("结束时间必须晚于开始")
return vfield_validator:单字段校验(可访问其他字段的值)model_validator:整模型校验(跨字段逻辑)- 校验器在约束之后执行;抛
ValueError转成 422 field_validator/model_validator是 Pydantic v2 的 API,v1 的@validator已弃用
序列化
user = UserCreate(name="alice", age=20)
data = user.model_dump() # 转 dict
json_str = user.model_dump_json() # 转 JSON 字符串
user2 = UserCreate.model_validate(data) # 从 dict 构建+校验| 方法 | 用途 |
|---|---|
model_dump() |
转 dict(内部传递) |
model_dump_json() |
转 JSON(响应) |
model_validate() |
从 dict 构建并校验 |
model_copy(update=...) |
部分修改(替代 Builder) |
FastAPI 中:请求体自动 model_validate,响应模型自动 model_dump,手写序列化代码基本不需要。
面试追问
- Pydantic 和 dataclass 的区别? Pydantic 有校验、序列化、文档集成;dataclass 只是样板代码生成。FastAPI 用 Pydantic
- 校验失败返回什么? 422,响应体是字段级错误明细(loc/msg/type)。不是 400
- 嵌套模型怎么校验? 递归校验整棵模型树,一层错全报错。list[Model] 直接声明
- field_validator 和 model_validator? 前者单字段(可读其他字段),后者整模型跨字段逻辑。旧 @validator 已弃用
- 响应模型怎么过滤字段? 响应类型用 UserOut(不含 password 字段),FastAPI 自动按模型序列化