Migrations¶
Database schema migrations are managed with Alembic using SQLAlchemy 2.0 models.
Structure¶
migrations/
alembic.ini # Alembic configuration
env.py # Migration environment setup
versions/ # Migration scripts (auto-generated)
Running Migrations¶
Apply all pending migrations¶
Rollback one migration¶
Show current revision¶
Show migration history¶
Creating a New Migration¶
Auto-generate from model changes¶
This compares the current database schema against your SQLAlchemy models and generates a migration script.
Manual migration¶
Then edit the generated file in migrations/versions/.
Connection Configuration¶
Alembic uses the synchronous database URL from CommonSettings:
# In migrations/env.py
from orion_common.config import get_settings
settings = get_settings()
config.set_main_option("sqlalchemy.url", settings.database_url_sync)
| URL Type | Property | Driver |
|---|---|---|
| Async (app) | settings.database_url |
asyncpg |
| Sync (migrations) | settings.database_url_sync |
psycopg2 |
Migration Script Template¶
"""Add publish_records table.
Revision ID: abc123
Revises: def456
Create Date: 2024-03-12 10:00:00.000000
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
revision: str = "abc123"
down_revision: Union[str, None] = "def456"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.create_table(
"publish_records",
sa.Column("id", sa.UUID(), nullable=False),
sa.Column("content_id", sa.UUID(), nullable=False),
sa.Column("platform", sa.String(50), nullable=False),
sa.Column("status", sa.String(20), nullable=False),
sa.Column("published_at", sa.DateTime(timezone=True)),
sa.PrimaryKeyConstraint("id"),
sa.ForeignKeyConstraint(["content_id"], ["contents.id"]),
)
def downgrade() -> None:
op.drop_table("publish_records")
Best Practices¶
Always review auto-generated migrations
Alembic's autogenerate can miss certain changes (e.g., column renames are detected as drop + add). Always review generated scripts before applying.
- Test migrations against a fresh database and a populated database
- Never modify a migration that has been applied to production
- Include both
upgrade()anddowngrade()functions - Use descriptive migration messages