db-migration by awais68/phase-5-cloud-deployment
npx skills add https://github.com/awais68/phase-5-cloud-deployment --skill db-migration专为 SQLModel/FastAPI 项目提供专业的 Alembic 迁移管理,具备安全的模式演进和回滚能力。
| 命令 | 用途 |
|---|---|
alembic init alembic | 在项目中初始化 Alembic |
alembic revision --autogenerate -m "message" | 根据模型变更生成迁移 |
alembic revision -m "message" | 手动创建空迁移 |
alembic upgrade head | 应用所有待处理的迁移 |
alembic upgrade +1 | 一次应用一个迁移 |
Expert Alembic migration management for SQLModel/FastAPI projects with safe schema evolution and rollback capabilities.
| Command | Purpose |
|---|---|
alembic init alembic | Initialize Alembic in project |
alembic revision --autogenerate -m "message" | Generate migration from model changes |
alembic revision -m "message" | Create empty migration manually |
alembic upgrade head | Apply all pending migrations |
alembic upgrade +1 |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
alembic downgrade -1 | 回滚最后一次迁移 |
alembic downgrade base | 回滚所有迁移 |
alembic current | 显示当前版本 |
alembic history | 显示迁移历史 |
alembic init alembic
# alembic.ini
sqlalchemy.url = driver://user:pass@localhost/dbname
file_template = %%(year)s_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d_%%(rev)s_%%(slug)s
timezone = UTC
# alembic/env.py
from logging.config import fileConfig
from sqlalchemy import pool
from sqlalchemy.engine import Connection
from alembic.runtime.migration import MigrationContext
from sqlmodel import SQLModel, create_engine
from myapp.models import * # 导入所有 SQLModel 类
config = context.config
config.set_main_option("sqlalchemy.url", "postgresql://user:pass@localhost/dbname")
target_metadata = SQLModel.metadata
def run_migrations_offline() -> None:
"""在'离线'模式下运行迁移。"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online() -> None:
"""在'在线'模式下运行迁移。"""
connectable = create_engine(
config.get_main_option("sqlalchemy.url"),
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
# 根据模型差异自动生成迁移
alembic revision --autogenerate -m "add_fees_table"
# 指定版本范围
alembic revision --autogenerate -m "add_user_email" --rev-id=abc123
# 为手动更改创建空迁移
alembic revision -m "add_status_column"
# alembic/versions/2024_01_15_1200_add_fees_table.py
"""add_fees_table
Revision ID: abc123
Revises: def456
Create Date: 2024-01-15 12:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
from sqlmodel import SQLModel
# 版本标识符
revision = 'abc123'
down_revision = 'def456'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.create_table(
'fees',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('student_id', sa.Integer(), nullable=False),
sa.Column('amount', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False, default='pending'),
sa.Column('due_date', sa.DateTime(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.Column('updated_at', sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.PrimaryKeyConstraint('id'),
sa.ForeignKeyConstraint(['student_id'], ['students.id']),
)
op.create_index('ix_fees_student_id', 'fees', ['student_id'])
op.create_index('ix_fees_status', 'fees', ['status'])
def downgrade() -> None:
op.drop_index('ix_fees_status', table_name='fees')
op.drop_index('ix_fees_student_id', table_name='fees')
op.drop_table('fees')
# alembic/versions/2024_01_16_0900_add_fees_description.py
"""add_fees_description
Revision ID: ghi789
Revises: abc123
Create Date: 2024-01-16 09:00:00.000000
"""
from alembic import op
def upgrade() -> None:
op.add_column('fees', sa.Column('description', sa.Text(), nullable=True))
def downgrade() -> None:
op.drop_column('fees', 'description')
# 升级到最新版本
alembic upgrade head
# 一次升级一步
alembic upgrade +1
# 升级到特定版本
alembic upgrade abc123
# 显示待处理的迁移而不应用
alembic show heads
alembic history --verbose
# 回滚一次迁移
alembic downgrade -1
# 回滚到特定版本
alembic downgrade abc123
# 回滚所有迁移(清空数据库)
alembic downgrade base
def downgrade() -> None:
# 始终在表之前删除索引
op.drop_index('ix_fees_status', table_name='fees')
op.drop_index('ix_fees_student_id', table_name='fees')
# 在表之前删除外键
op.drop_constraint('fees_student_id_fkey', 'fees', type_='foreignkey')
op.drop_table('fees')
# alembic/versions/2024_01_17_1400_update_fees_status.py
"""update_fees_status_values
Revision ID: jkl012
Revises: ghi789
Create Date: 2024-01-17 14:00:00.000000
"""
from alembic import op
from sqlalchemy import text
def upgrade() -> None:
# 更新现有记录
op.execute(
text("UPDATE fees SET status = 'pending' WHERE status = 'unpaid'")
)
def downgrade() -> None:
# 恢复状态值
op.execute(
text("UPDATE fees SET status = 'unpaid' WHERE status = 'pending'")
)
def upgrade() -> None:
# 添加新的枚举类型
op.execute("CREATE TYPE fee_status_new AS ENUM ('pending', 'paid', 'overdue', 'waived')")
# 将数据复制到新类型
op.execute("ALTER TABLE fees ALTER COLUMN status TYPE fee_status_new USING status::text::fee_status_new")
# 删除旧类型
op.execute("DROP TYPE fee_status_old")
def downgrade() -> None:
# 反转该过程
op.execute("ALTER TABLE fees ALTER COLUMN status TYPE VARCHAR(20)")
op.execute("DROP TYPE fee_status_new")
alembic upgrade 然后 alembic downgradeDROP TABLE IF EXISTS、DROP COLUMN IF EXISTS| 技能 | 集成点 |
|---|---|
@sqlmodel-crud | 模型变更触发迁移 |
@fastapi-app | 迁移在启动时或通过 CLI 运行 |
@jwt-auth | 可能需要在迁移期间处理身份验证 |
alembic revision --autogenerate -m "describe_change"
# 然后审查并编辑生成的文件
# 检查:
# - 列类型是否匹配 SQLModel 定义
# - 外键约束是否正确
# - 索引是否合适
# - 是否设置了默认值
# 在测试环境中
alembic downgrade base
alembic upgrade head
# 验证所有数据是否完整
# 对于大表,使用批量更新
def upgrade():
op.execute("""
UPDATE fees SET status = 'pending'
WHERE status IS NULL
LIMIT 10000
""")
project/
├── alembic/
│ ├── env.py # 迁移配置
│ ├── script.py.mako # 新迁移的模板
│ ├── README # Alembic 文档
│ └── versions/
│ ├── 2024_01_15_1200_add_fees_table.py
│ └── 2024_01_16_0900_add_fees_description.py
├── myapp/
│ └── models.py # SQLModel 定义
└── alembic.ini # Alembic 配置
每周安装次数
1
代码库
首次出现
1 天前
安全审计
安装于
amp1
cline1
opencode1
cursor1
kimi-cli1
codex1
| Apply one migration at a time |
alembic downgrade -1 | Rollback last migration |
alembic downgrade base | Rollback all migrations |
alembic current | Show current revision |
alembic history | Show migration history |
alembic init alembic
# alembic.ini
sqlalchemy.url = driver://user:pass@localhost/dbname
file_template = %%(year)s_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d_%%(rev)s_%%(slug)s
timezone = UTC
# alembic/env.py
from logging.config import fileConfig
from sqlalchemy import pool
from sqlalchemy.engine import Connection
from alembic.runtime.migration import MigrationContext
from sqlmodel import SQLModel, create_engine
from myapp.models import * # Import all SQLModel classes
config = context.config
config.set_main_option("sqlalchemy.url", "postgresql://user:pass@localhost/dbname")
target_metadata = SQLModel.metadata
def run_migrations_offline() -> None:
"""Run migrations in 'offline' mode."""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online() -> None:
"""Run migrations in 'online' mode."""
connectable = create_engine(
config.get_main_option("sqlalchemy.url"),
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
# Generate migration automatically based on model diffs
alembic revision --autogenerate -m "add_fees_table"
# With specific revision range
alembic revision --autogenerate -m "add_user_email" --rev-id=abc123
# Create empty migration for manual changes
alembic revision -m "add_status_column"
# alembic/versions/2024_01_15_1200_add_fees_table.py
"""add_fees_table
Revision ID: abc123
Revises: def456
Create Date: 2024-01-15 12:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
from sqlmodel import SQLModel
# revision identifiers
revision = 'abc123'
down_revision = 'def456'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.create_table(
'fees',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('student_id', sa.Integer(), nullable=False),
sa.Column('amount', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False, default='pending'),
sa.Column('due_date', sa.DateTime(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.Column('updated_at', sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.PrimaryKeyConstraint('id'),
sa.ForeignKeyConstraint(['student_id'], ['students.id']),
)
op.create_index('ix_fees_student_id', 'fees', ['student_id'])
op.create_index('ix_fees_status', 'fees', ['status'])
def downgrade() -> None:
op.drop_index('ix_fees_status', table_name='fees')
op.drop_index('ix_fees_student_id', table_name='fees')
op.drop_table('fees')
# alembic/versions/2024_01_16_0900_add_fees_description.py
"""add_fees_description
Revision ID: ghi789
Revises: abc123
Create Date: 2024-01-16 09:00:00.000000
"""
from alembic import op
def upgrade() -> None:
op.add_column('fees', sa.Column('description', sa.Text(), nullable=True))
def downgrade() -> None:
op.drop_column('fees', 'description')
# Upgrade to latest revision
alembic upgrade head
# Upgrade one step at a time
alembic upgrade +1
# Upgrade to specific revision
alembic upgrade abc123
# Show pending migrations without applying
alembic show heads
alembic history --verbose
# Rollback one migration
alembic downgrade -1
# Rollback to specific revision
alembic downgrade abc123
# Rollback all migrations (empty database)
alembic downgrade base
def downgrade() -> None:
# Always drop indexes before table
op.drop_index('ix_fees_status', table_name='fees')
op.drop_index('ix_fees_student_id', table_name='fees')
# Drop foreign keys before table
op.drop_constraint('fees_student_id_fkey', 'fees', type_='foreignkey')
op.drop_table('fees')
# alembic/versions/2024_01_17_1400_update_fees_status.py
"""update_fees_status_values
Revision ID: jkl012
Revises: ghi789
Create Date: 2024-01-17 14:00:00.000000
"""
from alembic import op
from sqlalchemy import text
def upgrade() -> None:
# Update existing records
op.execute(
text("UPDATE fees SET status = 'pending' WHERE status = 'unpaid'")
)
def downgrade() -> None:
# Revert status values
op.execute(
text("UPDATE fees SET status = 'unpaid' WHERE status = 'pending'")
)
def upgrade() -> None:
# Add new enum type
op.execute("CREATE TYPE fee_status_new AS ENUM ('pending', 'paid', 'overdue', 'waived')")
# Copy data to new type
op.execute("ALTER TABLE fees ALTER COLUMN status TYPE fee_status_new USING status::text::fee_status_new")
# Drop old type
op.execute("DROP TYPE fee_status_old")
def downgrade() -> None:
# Reverse the process
op.execute("ALTER TABLE fees ALTER COLUMN status TYPE VARCHAR(20)")
op.execute("DROP TYPE fee_status_new")
alembic upgrade then alembic downgrade in testDROP TABLE IF EXISTS, DROP COLUMN IF EXISTS| Skill | Integration Point |
|---|---|
@sqlmodel-crud | Model changes trigger migrations |
@fastapi-app | Migrations run at startup or via CLI |
@jwt-auth | May need to handle auth during migrations |
alembic revision --autogenerate -m "describe_change"
# Then review and edit the generated file
# Check that:
# - Column types match SQLModel definitions
# - Foreign key constraints are correct
# - Indexes are appropriate
# - Default values are set
# In test environment
alembic downgrade base
alembic upgrade head
# Verify all data is intact
# For large tables, use batch updates
def upgrade():
op.execute("""
UPDATE fees SET status = 'pending'
WHERE status IS NULL
LIMIT 10000
""")
project/
├── alembic/
│ ├── env.py # Migration configuration
│ ├── script.py.mako # Template for new migrations
│ ├── README # Alembic documentation
│ └── versions/
│ ├── 2024_01_15_1200_add_fees_table.py
│ └── 2024_01_16_0900_add_fees_description.py
├── myapp/
│ └── models.py # SQLModel definitions
└── alembic.ini # Alembic configuration
Weekly Installs
1
Repository
First Seen
1 day ago
Security Audits
Installed on
amp1
cline1
opencode1
cursor1
kimi-cli1
codex1