第3部:MySQL連携 Step 10 / 24

マイグレーション

マイグレーションは、データベースのスキーマ変更を管理する仕組み。Alembicを使って、テーブル構造の変更を安全に行います。

なぜマイグレーションが必要か

マイグレーションなしの問題

  • ✗ 本番DBを直接変更 → 履歴が残らない
  • ✗ チームで変更が衝突
  • ✗ 元に戻せない
  • ✗ どのバージョンか分からない

マイグレーションのメリット

  • ○ 変更履歴がコードで残る
  • ○ チームで共有できる
  • ○ ロールバック(元に戻す)可能
  • ○ 環境間で同じ構造を保証

Alembicのセットアップ

1. インストール

pip install alembic

2. 初期化

# プロジェクトルートで実行
alembic init alembic

# 以下のファイル構造が生成される
# alembic/
# ├── versions/     # マイグレーションファイル
# ├── env.py        # 環境設定
# └── script.py.mako
# alembic.ini       # 設定ファイル

3. alembic.ini の設定

# alembic.ini の該当行を変更
sqlalchemy.url = mysql+pymysql://myuser:mypassword@localhost:3306/myapp

4. env.py の設定

# alembic/env.py
from logging.config import fileConfig
from sqlalchemy import engine_from_config, pool
from alembic import context

# 追加: モデルをインポート
import sys
sys.path.append('.')
from models import Base  # あなたのモデル

config = context.config
fileConfig(config.config_file_name)

# 追加: メタデータを設定
target_metadata = Base.metadata

def run_migrations_offline():
    # ... 既存コード

def run_migrations_online():
    # ... 既存コード

マイグレーションの操作

マイグレーション作成(自動生成)

# モデルの変更を検出してマイグレーションを自動生成
alembic revision --autogenerate -m "create users and posts tables"

# alembic/versions/ に新しいファイルが作成される
# 例: 2024_01_15_1234_create_users_and_posts_tables.py

マイグレーション実行

# 最新まで適用
alembic upgrade head

# 1つだけ進める
alembic upgrade +1

# 特定のリビジョンまで
alembic upgrade abc123

ロールバック(元に戻す)

# 1つ前に戻す
alembic downgrade -1

# 特定のリビジョンまで戻す
alembic downgrade abc123

# 全部戻す(注意!)
alembic downgrade base

状態確認

# 現在のリビジョン確認
alembic current

# マイグレーション履歴
alembic history

# 適用予定のマイグレーション
alembic heads

マイグレーションファイルの例

"""create users and posts tables

Revision ID: abc123
Revises:
Create Date: 2024-01-15 10:30:00.000000
"""
from alembic import op
import sqlalchemy as sa

# revision identifiers
revision = 'abc123'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    # usersテーブル作成
    op.create_table(
        'users',
        sa.Column('id', sa.Integer(), nullable=False),
        sa.Column('email', sa.String(255), nullable=False),
        sa.Column('name', sa.String(100), nullable=False),
        sa.Column('password_hash', sa.String(255), nullable=False),
        sa.Column('created_at', sa.DateTime(), server_default=sa.func.now()),
        sa.Column('updated_at', sa.DateTime(), server_default=sa.func.now()),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('email')
    )
    op.create_index('ix_users_email', 'users', ['email'])

    # postsテーブル作成
    op.create_table(
        'posts',
        sa.Column('id', sa.Integer(), nullable=False),
        sa.Column('title', sa.String(255), nullable=False),
        sa.Column('content', sa.Text(), nullable=False),
        sa.Column('author_id', sa.Integer(), nullable=False),
        sa.Column('created_at', sa.DateTime(), server_default=sa.func.now()),
        sa.Column('updated_at', sa.DateTime(), server_default=sa.func.now()),
        sa.ForeignKeyConstraint(['author_id'], ['users.id'], ondelete='CASCADE'),
        sa.PrimaryKeyConstraint('id')
    )
    op.create_index('ix_posts_author_id', 'posts', ['author_id'])


def downgrade():
    op.drop_table('posts')
    op.drop_table('users')

よく使う操作

# カラム追加
def upgrade():
    op.add_column('posts', sa.Column('published', sa.Boolean(), default=False))

def downgrade():
    op.drop_column('posts', 'published')


# カラム名変更
def upgrade():
    op.alter_column('users', 'name', new_column_name='display_name')

def downgrade():
    op.alter_column('users', 'display_name', new_column_name='name')


# インデックス追加
def upgrade():
    op.create_index('ix_posts_created_at', 'posts', ['created_at'])

def downgrade():
    op.drop_index('ix_posts_created_at', 'posts')

Docker環境での実行

# コンテナ内でマイグレーション実行
docker compose exec backend alembic upgrade head

# 開発時のワークフロー
# 1. モデルを変更
# 2. マイグレーション生成
docker compose exec backend alembic revision --autogenerate -m "add published column"

# 3. 生成されたファイルを確認・編集

# 4. マイグレーション実行
docker compose exec backend alembic upgrade head

まとめ

  • Alembicでスキーマ変更を管理
  • --autogenerateで自動生成、手動確認も忘れずに
  • upgrade headで適用、downgrade -1で戻す
  • マイグレーションファイルはGitで管理
FastAPI + MySQL 次へ:認証の基礎