マイグレーション
マイグレーションは、データベースのスキーマ変更を管理する仕組み。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で管理