Alembic 数据库迁移

Alembic 数据库迁移 Alembic 数据库迁移SQLAlchemy 官方数据库迁移工具用于 Python 项目的数据库 schema 版本管理。一、核心概念迁移文件alembic/versions/下每个.py文件是一个版本包含upgrade()和downgrade()版本链每个迁移记录down_revision依赖的上一个版本形成线性链alembic_version表数据库中的单行表记录当前已应用的版本号每次upgrade head会把未应用的迁移按链顺序执行并更新alembic_version二、常用命令cdserver uv run alembic current# 查看当前版本uv run alembichistory# 查看迁移链uv run alembic check# 检查模型与数据库是否一致uv run alembic revision--autogenerate-m描述# 自动生成迁移uv run alembic upgradehead# 应用所有未执行迁移uv run alembic upgraderev# 升级到指定版本uv run alembic downgrade-1# 回滚一个版本uv run alembic upgradehead--sql# 输出 SQL 而不执行 文件导出三、标准工作流修改 SQLModel 模型定义uv run alembic revision --autogenerate -m 描述变更审查生成的迁移文件autogenerate 非 100% 可靠uv run alembic upgrade head应用产出增量 SQLuv run alembic upgrade 上条rev:head --sql sql/migration_日期.sql四、server_default 规则数据库默认值必须在模型中声明Column(server_default...)或sa_column_kwargs不能只在迁移文件中手写场景写法时间戳server_defaulttext(now())布尔 falseserver_defaultfalse字符串server_defaulttext(value)— 必须用text()防止引号被错误转义五、迁移压缩Squash5.1 Alembic 无内置 squash 命令官方没有提供类似 Djangosquashmigrations的功能。alembic merge用于合并分叉分支多个 head创建指向多父节点的交汇迁移形成菱形结构。这是在加文件而非减文件与压缩无关。--splice1.18.5 新增仅允许merge操作非 head 节点仍然是分支合并不是压缩。Alembic 维护者 zzzeek 在 Discussion #1259 中给出的 squash 方法是手动 autogenerate 空库法。全量压缩和部分合并原理相同仅参数不同。5.2 全量压缩base → head整个链替换为一个初始迁移步骤操作1确保模型与数据库无差异alembic check2创建空库设DATABASE_URL指向空库3alembic revision --autogenerate -m initial schema→down_revision None4空库上upgrade head验证5导出init.sql删旧迁移文件6开发库UPDATE alembic_version SET version_num 新ID5.3 部分合并链中间段只合并中间 B→C→D 为 B’保留首尾 A 和 EA → B → C → D → E (head) └── B ──┘ (B 替代 B/C/DE 接在 B 后)关键技巧空库 schema 跑到 D 状态但 alembic_version 回退到 Aautogenerate 就会把 A→D 的全部差异生成到一个迁移里。# 1. 空库先跑到合并起点 A$env:DATABASE_URLpostgresqlasyncpg://.../arbai_squashuv run alembic upgrade A# 2. 再跑到合并终点 Dschema D 状态uv run alembic upgrade D# 3. 回退版本标记到 Apsql-darbai_squash-cUPDATE alembic_version SET version_num A;# 4. autogenerate 生成 B对比A 标记 vs D 实际 schemauv run alembic revision--autogenerate-msquash B C D# 5. 编辑 Bdown_revision A# 6. 编辑 Edown_revision B的新ID# 7. 删除 B、C、D 旧文件# 8. 开发库升级版本标记如果当前 D六、生产环境部署Alembic 适合开发环境使用不适合直接在生产环境执行Alembic 依赖项目代码和 SQLModel 模型导入与项目耦合太重生产部署不应附带完整开发依赖直接连生产库执行 autogenerate 有风险误判、连接中断等且难以审计实际会执行什么 SQL运维团队通常只需要执行确定的 DDL不需要了解 Python 迁移框架开发时通过 Alembic 生成增量 SQL 文件生产环境直接执行 SQL首次部署完整建库init.sql后续升级增量迁移按日期顺序执行migration_20260616.sql migration_20260620.sql七、常见坑7.1 手写迁移与模型不一致旧手动迁移的 DDL 和 SQLModel 模型定义不一致是常见问题。应始终以模型为唯一数据源autogenerate 生成迁移。7.2 字符串 server_default 引号转义server_defaultactive→ autogenerate 可能丢失外层引号 → 生成server_defaultactive→ SQL 变成DEFAULT active被当成标识符而非字符串。正确做法模型中使用server_defaulttext(active)autogenerate 能正确保留。7.3--sql输出中文乱码设置环境变量PYTHONUTF81PYTHONIOENCODINGutf-8 uv run alembic upgradehead--sqloutput.sql7.4 autogenerate 使用 sqlmodel.AutoStringautogenerate 会对Field(max_lengthN)的字段生成sqlmodel.sql.sqltypes.AutoString迁移文件中需import sqlmodel。7.5 布尔 server_default 不需要 text()server_defaultfalse对 Boolean 列是正确的 —false在 PostgreSQL 中是布尔字面量不会被当成标识符。