本文介绍了从应用程序代码内部使用 Alembic API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 SQLite 作为应用程序文件格式(请参阅此处了解您为什么要这样做)为我的基于 PySide 的桌面应用程序.也就是说,当用户使用我的应用程序时,他们的数据保存在他们机器上的单个数据库文件中.我正在使用 SQLAlchemy ORM 与数据库进行通信.

I am using SQLite as an application file format (see here for why you would want to do this) for my PySide-based desktop application. That is, when a user uses my app, their data is saved in a single database file on their machine. I am using the SQLAlchemy ORM to communicate with the databases.

当我发布应用程序的新版本时,我可能会修改数据库架构.我不希望用户每次更改架构时都必须丢弃他们的数据,因此我需要将他们的数据库迁移到最新格式.此外,我创建了很多临时数据库来保存数据的子集以供某些外部进程使用.我想用 alembic 创建这些数据库,以便用正确的版本标记它们.

As I release new versions of the application, I may modify the database schema. I don't want users to have to throw away their data every time I change the schema, so I need to migrate their databases to the newest format. Also, I create temporary databases a lot to save subsets of the data for use with some external processes. I want to create these databases with alembic so they are tagged with the proper version.

我有几个问题:

  • 有没有办法从我的 Python 代码内部调用 alembic?我认为必须对纯 Python 模块使用 Popen 很奇怪,但文档只是从命令行使用 alembic.主要是,我需要将数据库位置更改为用户数据库所在的位置.

  • Is there a way to call alembic from inside my Python code? I think it's weird to have to use Popen to a pure Python module, but the docs just use alembic from the command line. Mainly, I need to change the database location to wherever the user's database is located.

如果这不可能,我可以在不编辑 .ini 文件的情况下从命令行指定新的数据库位置吗?这将使通过 Popen 调用 alembic 不是什么大问题.

If that's not possible, can I specify a new database location from the command line without editing the .ini file? This would make calling alembic through Popen not a big deal.

我看到 alembic 将其版本信息保存在一个名为 alembic_version 的简单表下,其中一列名为 version_num,一行指定版本.我可以在我的架构中添加一个 alembic_version 表并在我创建新数据库时用最新版本填充它,这样就没有开销了吗?这是一个好主意吗?我应该只使用 alembic 来创建所有数据库吗?

I see that alembic keeps its version information under a simple table called alembic_version, with one column called version_num and a single row specifying the version. Can I add an alembic_version table to my schema and populate it with the latest version when I create new databases so there is no overhead? Is that even a good idea; should I just use alembic to create all databases?

我的 alembic 非常适合用于在我的项目目录中进行开发的单个数据库.我想使用 alembic 在任意位置方便地迁移和创建数据库,最好通过某种 Python API 而不是命令行.此应用程序也被 cx_Freeze 冻结,以防万一.

I have alembic working great for the single database I use to develop with in my project's directory. I want to use alembic to conveniently migrate and create databases in arbitrary locations, preferably through some sort of Python API, and not the command line. This application is also frozen with cx_Freeze, in case that makes a difference.

谢谢!

推荐答案

这是我将我的软件连接到 alembic 后学到的:

Here's what I've learned after hooking up my software to alembic:

是的.在撰写本文时,alembic 的主要入口点是 al.config.main,这样就可以导入自己调用了,例如:

Yes. As of this writing the main entry point for alembic is alembic.config.main, so you can import it and call it yourself, for example:

import alembic.config
alembicArgs = [
    '--raiseerr',
    'upgrade', 'head',
]
alembic.config.main(argv=alembicArgs)

请注意,alembic 在当前目录(即 os.getcwd())中查找迁移.我在调用 alembic 之前使用 os.chdir(migration_directory) 处理了这个问题,但可能有更好的解决方案.

Note that alembic looks for migrations in the current directory (i.e., os.getcwd()). I've handled this by using os.chdir(migration_directory) before calling alembic, but there may be a better solution.

是的.关键在于 -x 命令行参数.来自 alembic -h(令人惊讶的是,我无法在文档中找到命令行参数参考):

Yes. The key lies in the -x command line argument. From alembic -h (surprisingly, I wasn't able to find a command line argument reference in the docs):

optional arguments:
 -x X                  Additional arguments consumed by custom env.py
                       scripts, e.g. -x setting1=somesetting -x
                       setting2=somesetting

因此您可以创建自己的参数,例如dbPath,然后在env.py中截取:

So you can create your own parameter, e.g. dbPath, and then intercept it in env.py:

alembic -x dbPath=/path/to/sqlite.db 升级头

然后例如在 env.py 中:

def run_migrations_online():
    # get the alembic section of the config file
    ini_section = config.get_section(config.config_ini_section)

    # if a database path was provided, override the one in alembic.ini
    db_path = context.get_x_argument(as_dictionary=True).get('dbPath')
    if db_path:
        ini_section['sqlalchemy.url'] = db_path

    # establish a connectable object as normal
    connectable = engine_from_config(
        ini_section,
        prefix='sqlalchemy.',
        poolclass=pool.NullPool)

    # etc

当然,您也可以在 alembic.config.main 中使用 argv 提供 -x 参数.

Of course, you can supply the -x parameter using argv in alembic.config.main, too.

我同意 @davidism 关于使用迁移 vs metadata.create_all() :)

I agree with @davidism about using migrations vs metadata.create_all() :)

这篇关于从应用程序代码内部使用 Alembic API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-10 14:33