现在位置: 首页 > FastAPI 教程 > 正文

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 的数据引擎,通过类型提示定义数据结构。

实例

from pydantic import BaseModel, ConfigDict

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

实例

# 文件路径:schemas.py
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

实例

# 文件路径:routers/posts.py(创建 POST 路由的示例)
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.pyschemas.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 类型驱动架构的精髓——先定义数据形状,路由和文档自动生成。