You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python应用包中分发Alembic迁移脚本并支持用户执行迁移

解决Alembic迁移文件随Python包发布的问题

核心思路

要让用户通过pip安装后直接执行数据库迁移,关键是把Alembic的配置文件和迁移脚本放到Python包目录内,通过打包工具将这些文件一并分发,同时让Alembic能正确定位到它们。

步骤1:调整目录结构

把migrations目录移动到my_app包内部,这样pip安装时会将其和源码一起部署到虚拟环境的site-packages中:

my-app/
    my_app/
        migrations/
            versions/
                ...  # 迁移脚本
            env.py
        ... # 源代码
    alembic.ini  # 后续可移到包内,或通过代码定位
    MANIFEST.in
    README.rst
    setup.py

步骤2:修改Alembic配置与脚本

  1. 更新alembic.ini
    修改script_location指向包内的migrations目录:

    script_location = my_app/migrations
    

    如果把alembic.ini也移到my_app包内,路径改为my_app/alembic.ini,后续通过代码定位会更方便。

  2. 调整env.py的数据库URL配置
    不要在env.py中硬编码数据库URL,改为从应用配置读取,比如:

    # my_app/migrations/env.py
    from my_app.config import get_database_url  # 假设你有这个配置函数
    
    config.set_main_option("sqlalchemy.url", get_database_url())
    

    这样用户可以通过应用的配置文件(如环境变量、自定义配置文件等)设置数据库连接,无需修改Alembic相关文件。

步骤3:配置打包参数(setup.py)

确保迁移文件和配置被包含到分发包中:

# setup.py
from setuptools import setup, find_packages

setup(
    name="my-app",
    version="0.1.0",
    packages=find_packages(),
    # 包含MANIFEST.in指定的文件
    include_package_data=True,
    # 精确指定要包含的迁移文件(可选,与MANIFEST.in互补)
    package_data={
        "my_app": [
            "migrations/*.py",
            "migrations/versions/*.py",
            "alembic.ini"  # 如果移到包内的话
        ]
    },
    # 推荐:提供自定义命令让用户直接执行迁移
    entry_points={
        "console_scripts": [
            "my-app-upgrade=my_app.migrations.run_upgrade:main",
        ]
    },
    install_requires=[
        "sqlalchemy",
        "alembic"
    ]
)

步骤4:配置MANIFEST.in

添加以下内容,确保源码分发包(sdist)包含必要文件:

# MANIFEST.in
include my_app/migrations/*.py
recursive-include my_app/migrations/versions *.py
include my_app/alembic.ini  # 如果移到包内的话
include alembic.ini  # 若保留在根目录则添加这行

步骤5:让用户轻松执行迁移

推荐用自定义入口点命令替代直接调用alembic,避免用户手动指定配置文件路径:

  1. 在my_app/migrations/run_upgrade.py中编写执行逻辑:
from alembic.config import Config
from alembic import command
from importlib.resources import files

def main():
    # 定位包内的alembic.ini
    ini_path = files("my_app").joinpath("alembic.ini")
    alembic_cfg = Config(str(ini_path))
    # 执行迁移到最新版本
    command.upgrade(alembic_cfg, "head")

if __name__ == "__main__":
    main()
  1. 用户安装后,直接运行以下命令即可完成迁移:
my-app-upgrade

相关概念快速说明

  • 源码分发包(sdist):包含所有源代码、配置和资源文件的压缩包,MANIFEST.in用来指定哪些文件需要纳入。
  • Wheel包(bdist_wheel):预编译的二进制包,安装速度更快,include_package_data=True会把指定的非代码文件也打包进去。
  • include_package_data:告诉setuptools读取MANIFEST.in的规则,将非代码文件包含到分发包中。
  • package_data:直接指定包内需要包含的非代码文件,比MANIFEST.in更精确,适合细粒度控制。

内容的提问来源于stack exchange,提问作者Jérôme

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 01:05:26