初始化配置

Alembic 是 SQLAlchemy 的数据库迁移工具,用来版本化管理数据库表结构的变更。

一、为什么需要 Alembic

开发过程中表结构会不断变化(加字段、改类型、删表),手动管理很乱:

方式问题
Base.metadata.create_all()只能建表,不能改表、删表
手动写 SQL容易出错,多人协作对不上
删库重建数据丢失

Alembic 的做法:每次表结构变更生成一个迁移脚本,可以向前执行(upgrade)也可以回滚(downdown),所有变更都有记录。

二、安装

pip install alembic

三、初始化

在项目根目录执行:

alembic init alembic

会生成以下结构:

项目目录/
├── alembic/             ← Alembic 的工作目录
│   ├── versions/        ← 迁移脚本存放处
│   ├── env.py           ← 环境配置(重要,需要改)
│   ├── script.py.mako   ← 迁移脚本模板
│   └── README
├── alembic.ini          ← Alembic 配置文件(重要,需要改)
├── database.py
└── models.py

四、配置 alembic.ini

打开 alembic.ini,找到这一行:

# sqlalchemy.url = driver://user:pass@localhost/dbname

改成你的数据库连接地址:

# SQLite
sqlalchemy.url = sqlite:///./test.db

# MySQL
sqlalchemy.url = mysql+pymysql://root:123456@localhost:3306/mydb

# PostgreSQL
sqlalchemy.url = postgresql://postgres:123456@localhost:5432/mydb

也可以不改这里,在 env.py 里动态设置(后面会讲)。

五、配置 env.py

env.py 是 Alembic 的核心配置文件,需要改两个地方。

5.1 导入你的 Model

在文件顶部加上:

# 导入所有 Model,这样 Alembic 才知道有哪些表
from models import Base

如果 Model 分散在多个文件中,全部导入:

from models.user import User
from models.article import Article
from models.tag import Tag

5.2 设置 target_metadata

找到这一行:

target_metadata = None

改成:

target_metadata = Base.metadata

这一行告诉 Alembic:「用这些 Model 的定义作为目标状态,和数据库当前状态对比,自动生成差异」。

5.3 完整 env.py(关键部分)

from logging.config import fileConfig
from sqlalchemy import engine_from_config, pool
from alembic import context

# ---------- 你加的部分 ----------
from models import Base
# --------------------------------

config = context.config

if config.config_file_name is not None:
    fileConfig(config.config_file_name)

# ---------- 你改的部分 ----------
target_metadata = Base.metadata
# --------------------------------


def run_migrations_offline() -> None:
    """离线模式(只生成 SQL,不执行)"""
    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 = engine_from_config(
        config.get_section(config.config_ini_section, {}),
        prefix="sqlalchemy.",
        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 current

正常输出类似:

INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.

如果报错 Can't locate revision identified by 'xxx',通常是因为数据库里有旧的迁移记录但 versions/ 目录里没有对应脚本,删掉数据库文件重新来就行。