alembic
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAlembic Database Migrations
Alembic数据库迁移
Alembic is the migration tool for SQLAlchemy. It manages schema versioning through a directory of revision scripts linked by pointers, forming a linear (or branched) migration chain.
down_revisionAlembic是SQLAlchemy的迁移工具。它通过由指针链接的修订脚本目录来管理schema版本控制,形成线性(或分支)的迁移链。
down_revisionEnvironment Setup
环境设置
Initialize the Migration Environment
初始化迁移环境
bash
undefinedbash
undefinedGeneric single-database (most common)
通用单数据库(最常用)
alembic init alembic
alembic init alembic
pyproject.toml-integrated (modern projects)
集成pyproject.toml(现代项目)
alembic init --template pyproject alembic
alembic init --template pyproject alembic
Async DBAPI support
异步DBAPI支持
alembic init --template async alembic
Use `pyproject` template for modern Python projects that already have a `pyproject.toml`. It separates source-code config (in `pyproject.toml`) from deployment config (database URL, logging in `alembic.ini`).alembic init --template async alembic
对于已包含`pyproject.toml`的现代Python项目,使用`pyproject`模板。它将源代码配置(在`pyproject.toml`中)与部署配置(数据库URL、`alembic.ini`中的日志配置)分离。Project Structure
项目结构
yourproject/
├── alembic.ini # DB URL, logging, deployment config
├── pyproject.toml # Source/code config (pyproject template)
└── alembic/
├── env.py # Migration runner — customize here
├── script.py.mako # Template for new revision files
└── versions/
├── 3512b954651e_add_account.py
└── ae1027a6acf_add_column.pyyourproject/
├── alembic.ini # 数据库URL、日志、部署配置
├── pyproject.toml # 源代码配置(pyproject模板)
└── alembic/
├── env.py # 迁移运行器——在此处自定义
├── script.py.mako # 新修订文件的模板
└── versions/
├── 3512b954651e_add_account.py
└── ae1027a6acf_add_column.pyConfigure alembic.ini
alembic.ini配置alembic.ini
alembic.iniSet the database URL:
ini
sqlalchemy.url = postgresql+psycopg2://user:pass@localhost/mydbURL escaping: Special characters in passwords must be percent-encoded, then doubled for ConfigParser interpolation:
%python
import urllib.parse
from sqlalchemy import URL
url = URL.create("postgresql+psycopg2", username="scott", password="P@ss%rd", host="localhost")设置数据库URL:
ini
sqlalchemy.url = postgresql+psycopg2://user:pass@localhost/mydbURL转义:密码中的特殊字符必须进行百分比编码,然后为了适配ConfigParser插值,需将加倍:
%python
import urllib.parse
from sqlalchemy import URL
url = URL.create("postgresql+psycopg2", username="scott", password="P@ss%rd", host="localhost")Renders as: postgresql+psycopg2://scott:P%40ss%25rd@localhost
渲染结果:postgresql+psycopg2://scott:P%40ss%25rd@localhost
In alembic.ini: postgresql+psycopg2://scott:P%%40ss%%25rd@localhost
在alembic.ini中:postgresql+psycopg2://scott:P%%40ss%%25rd@localhost
**Never hard-code production credentials.** Read the URL from an environment variable in `env.py` instead:
```python
**切勿硬编码生产环境凭据**。请改为在`env.py`中从环境变量读取URL:
```pythonenv.py
env.py
import os
config.set_main_option("sqlalchemy.url", os.environ["DATABASE_URL"])
undefinedimport os
config.set_main_option("sqlalchemy.url", os.environ["DATABASE_URL"])
undefinedEnable Autogenerate in env.py
env.py在env.py
中启用自动生成
env.pyLink the application's SQLAlchemy so Alembic can diff schema:
MetaDatapython
undefined关联应用的SQLAlchemy ,以便Alembic可以对比schema差异:
MetaDatapython
undefinedenv.py — replace the None assignment
env.py ——替换None赋值
from myapp.models import Base
target_metadata = Base.metadata
undefinedfrom myapp.models import Base
target_metadata = Base.metadata
undefinedConstraint Naming Conventions
约束命名规范
Always configure a naming convention. Autogenerate cannot detect anonymously named constraints, and databases use incompatible auto-naming schemes (PostgreSQL vs Oracle differ significantly).
Set this on the used by the declarative base:
MetaDatapython
from sqlalchemy import MetaData
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
metadata = MetaData(naming_convention={
"ix": "ix_%(column_0_label)s",
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_`%(constraint_name)s`",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s",
})This allows and column flags to produce consistently named constraints across databases, and allows autogenerate to detect and drop them reliably.
unique=Trueindex=True务必配置命名规范。自动生成无法检测匿名命名的约束,且不同数据库使用不兼容的自动命名方案(PostgreSQL与Oracle差异显著)。
在声明式基类使用的上设置:
MetaDatapython
from sqlalchemy import MetaData
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
metadata = MetaData(naming_convention={
"ix": "ix_%(column_0_label)s",
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_`%(constraint_name)s`",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s",
})这使得和列标记可以在不同数据库中生成一致命名的约束,并且自动生成可以可靠地检测和删除这些约束。
unique=Trueindex=TrueCreating and Writing Migrations
创建与编写迁移
Generate a Revision
生成修订版本
bash
undefinedbash
undefinedManual (empty script)
手动创建(空脚本)
alembic revision -m "add account table"
alembic revision -m "add account table"
Autogenerate from model diff
从模型差异自动生成
alembic revision --autogenerate -m "add account table"
**Always review autogenerated scripts** before running them. Autogenerate cannot detect: table renames, column renames, or anonymously named constraints.alembic revision --autogenerate -m "add account table"
**运行前务必检查自动生成的脚本**。自动生成无法检测:表重命名、列重命名或匿名命名的约束。Anatomy of a Revision File
修订文件结构
python
"""add account table
Revision ID: 1975ea83b712
Revises: <previous_rev_id or None>
Create Date: 2024-01-15 10:30:00
"""
revision = '1975ea83b712'
down_revision = None # None = first migration
branch_labels = None
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table(
'account',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('name', sa.String(50), nullable=False),
sa.Column('created_at', sa.DateTime, nullable=False),
)
def downgrade():
op.drop_table('account')Always implement . It enables rollback and is required for .
downgrade()alembic downgradepython
"""add account table
Revision ID: 1975ea83b712
Revises: <previous_rev_id or None>
Create Date: 2024-01-15 10:30:00
"""
revision = '1975ea83b712'
down_revision = None # None = 首次迁移
branch_labels = None
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table(
'account',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('name', sa.String(50), nullable=False),
sa.Column('created_at', sa.DateTime, nullable=False),
)
def downgrade():
op.drop_table('account')务必为每个修订版本实现。它支持回滚操作,是命令所必需的。
downgrade()alembic downgradeCommon Operations
常见操作
python
undefinedpython
undefinedAdd a column
添加列
op.add_column('account', sa.Column('email', sa.String(255)))
op.add_column('account', sa.Column('email', sa.String(255)))
Drop a column
删除列
op.drop_column('account', 'email')
op.drop_column('account', 'email')
Add named foreign key (naming convention resolves the name)
添加命名外键(命名规范会解析名称)
op.create_foreign_key(
None, 'order', 'account',
['account_id'], ['id']
)
op.create_foreign_key(
None, 'order', 'account',
['account_id'], ['id']
)
Drop constraint — use op.f() to bypass naming convention tokenization
删除约束——使用op.f()绕过命名规范的标记化处理
op.drop_constraint(op.f('fk_order_account_id_account'), 'order', type_='foreignkey')
op.drop_constraint(op.f('fk_order_account_id_account'), 'order', type_='foreignkey')
Create index
创建索引
op.create_index('ix_account_name', 'account', ['name'])
undefinedop.create_index('ix_account_name', 'account', ['name'])
undefinedRunning Migrations
运行迁移
bash
undefinedbash
undefinedUpgrade to latest
升级到最新版本
alembic upgrade head
alembic upgrade head
Upgrade to specific revision (partial ID works)
升级到指定修订版本(部分ID即可)
alembic upgrade ae10
alembic upgrade ae10
Upgrade N steps forward
向前升级N步
alembic upgrade +2
alembic upgrade +2
Downgrade to base (undo all)
回滚到初始状态(撤销所有迁移)
alembic downgrade base
alembic downgrade base
Downgrade N steps backward
向后回滚N步
alembic downgrade -1
undefinedalembic downgrade -1
undefinedInspecting State
状态检查
bash
undefinedbash
undefinedShow current DB revision
显示当前数据库修订版本
alembic current
alembic current
Show full history
显示完整历史
alembic history --verbose
alembic history --verbose
Show history range
显示指定范围的历史
alembic history -r1975ea:ae1027
alembic history -r1975ea:ae1027
Check if new migrations needed (CI-friendly)
检查是否需要新的迁移(适合CI环境)
alembic check
Use `alembic check` in CI pipelines to assert that all model changes have a corresponding migration committed.alembic check
在CI流水线中使用`alembic check`来确保所有模型变更都有对应的已提交迁移。Post-Write Code Formatting
写入后代码格式化
Configure auto-formatting of generated revision files in :
alembic.iniini
[post_write_hooks]
hooks = ruff
ruff.type = exec
ruff.executable = ruff
ruff.options = check --fix REVISION_SCRIPT_FILENAMEOr with :
pyproject.tomltoml
[[tool.alembic.post_write_hooks]]
name = "ruff"
type = "exec"
executable = "ruff"
options = "check --fix REVISION_SCRIPT_FILENAME"在中配置生成的修订文件的自动格式化:
alembic.iniini
[post_write_hooks]
hooks = ruff
ruff.type = exec
ruff.executable = ruff
ruff.options = check --fix REVISION_SCRIPT_FILENAME或者使用:
pyproject.tomltoml
[[tool.alembic.post_write_hooks]]
name = "ruff"
type = "exec"
executable = "ruff"
options = "check --fix REVISION_SCRIPT_FILENAME"Quick Reference
快速参考
| Command | Description |
|---|---|
| Initialize migration environment |
| Create empty revision |
| Generate revision from model diff |
| Apply all pending migrations |
| Roll back all migrations |
| Show current DB revision |
| List all revisions |
| Assert no pending migrations (CI) |
| 命令 | 描述 |
|---|---|
| 初始化迁移环境 |
| 创建空修订版本 |
| 从模型差异生成修订版本 |
| 应用所有待处理的迁移 |
| 回滚所有迁移 |
| 显示当前数据库修订版本 |
| 列出所有修订版本 |
| 断言无待处理迁移(适用于CI) |
Key Best Practices
核心最佳实践
- Configure naming conventions on before creating any migrations.
MetaData - Always review autogenerated scripts — renames are detected as add+drop pairs.
- Always implement for every revision.
downgrade() - Never hard-code database URLs; read from environment variables.
- Run in CI to catch missing migrations early.
alembic check - Use template for modern projects to keep source config separate from deployment config.
pyproject - Use when explicitly naming constraints in drop operations to bypass naming convention tokenization.
op.f()
- 在创建任何迁移前,在上配置命名规范。
MetaData - 务必检查自动生成的脚本——重命名会被检测为添加+删除的组合操作。
- 务必为每个修订版本实现。
downgrade() - 切勿硬编码数据库URL;从环境变量读取。
- 在CI中运行,尽早发现缺失的迁移。
alembic check - 对于现代项目使用模板,将源代码配置与部署配置分离。
pyproject - 在删除操作中显式命名约束时使用,以绕过命名规范的标记化处理。
op.f()
Additional Resources
额外资源
- — Deep dive on
references/env-configuration.mdcustomization, async support, multiple databases, andenv.py/include_namehooks.include_object - — What autogenerate detects and does not detect, type comparison, custom hooks, and
references/autogenerate-guide.mdin CI.alembic check
- ——深入讲解
references/env-configuration.md自定义、异步支持、多数据库以及env.py/include_name钩子。include_object - ——自动生成能检测和不能检测的内容、类型对比、自定义钩子以及CI中的
references/autogenerate-guide.md。alembic check