Pydantic Schema — データ検証とシリアライズ
この章ではPydantic Schemaを学び、ORMモデルとの責務分離を理解します。これはFastAPIの最も中核的な機能です。
なぜSchemaが必要なのか?
ORMモデル(models.py)はデータベース構造を定義しますが、APIのリクエスト/レスポンス検証には直接使用できません。
理由:ORMモデルにはデータベース専用のロジック(relationshipなど)が含まれており、すべてのフィールドをAPIに公開したくないためです。
Pydantic Schema純粋なデータクラスであり、APIの入力・出力検証とシリアライズを専門に担当します。
この三者(ORMモデル、Pydantic Schema、ルート)の関係:
客户端 → [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_modelFastAPIの最強の機能の1つです。宣言すると、FastAPIは:1. Schemaで宣言されていないORMオブジェクトのフィールドを自動的にフィルタリングします。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の型駆動アーキテクチャの真髄です——先にデータの形を定義すれば、ルートとドキュメントが自動生成されます。
その他の拡張