Pydantic Schema — 数据验证与序列化
本章你将学会 Pydantic Schema,理解它与 ORM 模型的职责分离,这是 FastAPI 最核心的特性。
为什么需要 Schema?
ORM 模型(models.py)定义数据库结构,但不能直接用于 API 的请求/响应校验。
原因:ORM 模型包含数据库专用逻辑(如 relationship),且不希望将所有字段暴露给 API。
Pydantic Schema 是纯数据类,专门负责 API 的输入输出校验和序列化。
这三者的关系:
客户端 → [Pydantic Schema 校验] → 路由函数 → [ORM 模型] → 数据库 客户端 ← [Pydantic Schema 序列化] ← 路由函数 ← [ORM 模型] ← 数据库
Pydantic Schema 基础
Pydantic V2 是 FastAPI 的数据引擎,通过类型提示定义数据结构。
实例
class ItemCreate(BaseModel):
"""创建请求的 Schema"""
name: str
price: float # 自动校验类型
is_offer: bool = False # 带默认值(可选字段)
class ItemResponse(BaseModel):
"""响应 Schema"""
id: int
name: str
price: float
# V2 写法:开启 ORM 模式,允许从 ORM 对象直接转换
model_config = ConfigDict(from_attributes=True)
定义博客的 Schema
实例
from pydantic import BaseModel, ConfigDict
from datetime import datetime
from typing import Optional
# ====== Category Schema ======
class CategoryBase(BaseModel):
name: str
slug: str
class CategoryResponse(CategoryBase):
id: int
model_config = ConfigDict(from_attributes=True)
# ====== Post Schema ======
class PostBase(BaseModel):
title: str
slug: str
summary: Optional[str] = None # Optional = 可为 None
content: str
category_id: int
class PostCreate(PostBase):
"""创建文章时的请求体 Schema"""
pass # 直接继承 PostBase,字段完全一致
class PostUpdate(BaseModel):
"""更新文章(所有字段可选)"""
title: Optional[str] = None
slug: Optional[str] = None
summary: Optional[str] = None
content: Optional[str] = None
category_id: Optional[int] = None
class PostResponse(PostBase):
"""返回给客户端的响应 Schema"""
id: int
created_at: datetime
updated_at: datetime
category: CategoryResponse # 嵌套 Schema:返回分类信息
model_config = ConfigDict(from_attributes=True)
# from_attributes=True 告诉 Pydantic:这个 Schema 可以从 ORM 对象创建
Pydantic V2 中,
model_config = ConfigDict(from_attributes=True)替代了 V1 中的class Config: orm_mode = True。这个配置允许你直接从 SQLAlchemy ORM 对象构建 Pydantic Schema:PostResponse.model_validate(post_orm_obj)。
在路由中使用 Schema
实例
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from database import get_db
from models import Post
from schemas import PostCreate, PostResponse
router = APIRouter(prefix="/posts", tags=["文章"])
# 声明 response_model=PostResponse 后:
# 1. FastAPI 自动将 ORM 对象转换为 Schema(序列化)
# 2. API 文档自动显示响应结构
@router.post("/", response_model=PostResponse, status_code=201)
def create_post(post_data: PostCreate, db: Session = Depends(get_db)):
"""
创建新文章
- post_data:请求体,FastAPI 自动按 PostCreate Schema 校验
- db:通过 Depends(get_db) 注入的数据库会话
"""
post = Post(**post_data.model_dump()) # model_dump() 将 Schema 转字典
db.add(post)
db.commit()
db.refresh(post) # 刷新,获取数据库自增 ID
return post # FastAPI 自动用 PostResponse 序列化
response_model是 FastAPI 最强的特性之一。声明后,FastAPI 会:1. 自动过滤 ORM 对象中不在 Schema 中声明的字段;2. 自动将 datetime 等类型转为 JSON 字符串;3. 生成精确的 OpenAPI 文档。
ORM 模型 vs Pydantic Schema 对照
| 方面 | SQLAlchemy ORM 模型 | Pydantic Schema |
|---|---|---|
| 定义位置 | models.py | schemas.py |
| 基类 | Base (DeclarativeBase) | BaseModel (Pydantic) |
| 职责 | 定义数据库表结构和关系 | 定义 API 输入输出格式和校验规则 |
| 与数据库关系 | 直接映射数据库表 | 不关心数据库,只关心 API 契约 |
| 字段声明 | Column(Integer, ...) | Python 类型提示:int, str |
| 序列化 | 不能直接转 JSON | 内置 .model_dump() 和 JSON 序列化 |
| 转换方向 | ORM → Schema:model_validate(obj) | Schema → ORM:Model(**schema.model_dump()) |
本章小结
本章你掌握了 FastAPI 最核心的 Pydantic Schema:BaseModel 定义请求/响应 Schema、from_attributes=True 开启 ORM 模式、response_model 自动序列化 ORM 对象、Schema 与 ORM 模型的职责分离原则。
这就是 FastAPI 类型驱动架构的精髓——先定义数据形状,路由和文档自动生成。
