如何在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配置与脚本
更新alembic.ini
修改script_location指向包内的migrations目录:script_location = my_app/migrations如果把
alembic.ini也移到my_app包内,路径改为my_app/alembic.ini,后续通过代码定位会更方便。调整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,避免用户手动指定配置文件路径:
- 在
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()
- 用户安装后,直接运行以下命令即可完成迁移:
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
相关产品推荐
相关产品推荐

