L?? ch02 — Alembic マイグレーション
テクノロジ系 / L13 db — データベース連携
L?? ch02 — Alembic マイグレーション
スキーマ変更を「コードと一緒に進化させる」仕組み
ゴール
- マイグレーションが必要な理由を説明できる
alembic init/revision/upgrade/downgradeの役割を理解- リビジョン (revision) ファイルの構造を読める
なぜマイグレーションが必要か
- 開発が進むとテーブル定義は変わる (カラム追加 / 型変更 / index 追加)
- 「全員の DB を同じ状態に揃える」「本番へ安全に反映する」 ために、
- 変更履歴をコード (git) で管理
- 適用 / ロールバックを自動化
この役目を担うのが Alembic (SQLAlchemy 公式)。
全体像
モデル変更 (models.py) ↓ alembic revision --autogenerate リビジョンファイル (versions/xxxx_add_users.py) ↓ alembic upgrade head DB スキーマ更新 (CREATE TABLE / ALTER TABLE)
各リビジョンは upgrade() と downgrade() をペアで持つ。
初期化
uv add alembic sqlalchemy # プロジェクト直下で 1 回だけ uv run alembic init alembic
生成物:
alembic/ ├── env.py # DB 接続・モデル参照 ├── script.py.mako # リビジョンの雛形 └── versions/ # 個々のリビジョンを置く場所 alembic.ini # 設定ファイル
新しいリビジョンを作る
# 1. 手書きで雛形だけ作る uv run alembic revision -m "create users table" # 2. モデル差分から自動生成 (env.py の target_metadata 設定が必要) uv run alembic revision --autogenerate -m "create users table"
versions/2026xxxx_create_users_table.py が生成される。
リビジョンファイルの構造
# versions/abc123_create_users.py
revision = "abc123" # このリビジョンの ID
down_revision = None # 1 つ前のリビジョン (なければ None)
def upgrade() -> None:
op.create_table(
"users",
sa.Column("id", sa.Integer, primary_key=True),
sa.Column("name", sa.String(50), nullable=False),
)
def downgrade() -> None:
op.drop_table("users")upgrade / downgrade の対称性が肝。
適用とロールバック
# 最新まで適用 uv run alembic upgrade head # 1 つ戻す uv run alembic downgrade -1 # 特定リビジョンへ uv run alembic upgrade abc123 # 現在の状態 uv run alembic current # 履歴 uv run alembic history
ありがちな失敗
| 症状 | 原因 | 対処 |
|---|---|---|
Can't locate revision | down_revision の繋ぎ間違い | alembic history でチェーン確認 |
| autogenerate が空 | target_metadata 未設定 | env.py でモデルの Base.metadata を渡す |
| 本番だけ壊れる | downgrade を書いてない / 試してない | ローカルで up→down→up を必ず通す |
drill
drill/ — リビジョンの upgrade / downgrade を穴埋めで完成させる
まとめ
- Alembic は スキーマ変更の git のような存在
- リビジョン =
upgrade+downgradeのペア - ローカルで「適用 → 戻す → 再適用」を試してから commit する習慣を
力試ししたい方は クイズ形式の演習(任意) もあります。読むだけでも十分です。