【问题标题】:Alembic migrate with existing SQLAlchemy engine使用现有的 SQLAlchemy 引擎进行 Alembic 迁移
【发布时间】:2018-06-29 05:24:32
【问题描述】:

我有一个在 sqlite 内存数据库上创建的 SQLAlchemy 声明性基础:

engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)

我将它用于单元测试逻辑。

有了这个,我在数据库中有我的表。但现在我希望使用 alembic 迁移某些东西。

AFAIK alembic 迁移使用 env.py run_migrations_online 并使用名为 engine_from_config 的 SQLAlchemy 函数在此处创建新引擎。

我希望解决的问题是有一种方法可以使用先前创建的连接(其中包含最近创建的表)进行 alembic 迁移。

我在我的测试脚本中使用了这个:Using Alembic API from inside application code,以便我的脚本在之前的create_all 调用之后执行以下操作:

import alembic.config
alembicArgs = ['--raiseerr', '-x', 'dbPath=sqlite:///:memory:', 'upgrade', 'head']
alembic.config.main(argv=alembicArgs

[请注意,我只会使用 Base.metadata.create_all(engine) 调用创建我的模式,但我的 alembic 版本不仅包含模式更改,它们还填充了一些目录表数据,这就是我打算在这里使用 alembic 的原因。事实上,如果我的 alembic 迁移包含一些“创建表”逻辑,那么这两个会发生冲突。因此,我可以安全地删除 create_all 调用,并仅依靠 alembic 在此处创建我的架构。]

已经修改了我的 alembic 的env.py

def run_migrations_online():
    ini_section = config.get_section(config.config_ini_section)

    db_path = context.get_x_argument(as_dictionary=True).get('dbPath')

    if db_path:
        ini_section['sqlalchemy.url'] = db_path

    connectable = engine_from_config(
        ini_section,
        prefix ... # everything from here the same as default env.py

据我所知,connectable=engine_from_config 在新的sqlite:///:memory: 数据库上创建了与新引擎的连接,这就是为什么我无法通过 alembic 升级先前在我的脚本中使用create_all(engine) 创建的数据库。

所以... TLDR;有没有办法将我以前存在的引擎连接(使用我创建的表)传递给 alembic,以便它可以迁移它? (我很确定我创建的 dbPath arg 在这里没有用,事实上,我只是在复制我引用的其他帖子使用的内容)。

【问题讨论】:

  • 您要生成修订版还是只进行升级?
  • @georgexsh 只是升级。
  • run_migrations_online 内部需要一个 connection 对象,您可以从现有引擎创建一个:connection = db.engine.connect(),它适用于我。
  • 是的,但是在以编程方式调用 alembic 时如何传递现有连接?
  • 所以这个数据库只要应用程序存在就存在,对吗?您打算实时运行迁移吗?这是如何运作的?你如何“热更新”你的模型?

标签: python sqlite sqlalchemy database-migration alembic


【解决方案1】:

您可以创建一个 alembic 配置实例并对其进行操作:

def migrate_in_memory(migrations_path, alembic_ini_path=None, connection=None, revision="head"):
    config = alembic.config.Config(alembic_ini_path)
    config.set_main_option('script_location', migrations_path)
    config.set_main_option('sqlalchemy.url', 'sqlite:///:memory:')
    if connection is not None:
        config.attributes['connection'] = connection
    alembic.command.upgrade(config, revision)

这可能需要一些微调,但这是事情的一般要点。

【讨论】:

  • 必须对此进行测试,但该解决方案如何确保我使用与主脚本中的连接引擎相同的连接引擎?我的意思是,声明要使用的内存数据库有一个问题,如果你声明两个独立的连接,那么你将有两个独立的内存数据库,所以你不能在同一个上工作,然后升级就会失败'不会发生在我之前宣布的同一件事上
  • 在这种情况下,我假设你有一个connection 对象?如果是这样,请在调用 upgrade 之前尝试调用:config.attributes['connection'] = connection
  • 是的,我知道了,帖子里这么说的。让我试试,我会回来找你的
  • mmm 似乎可以工作,但不能肯定地说,alembic 在执行 alembic.command.upgrade(config, "head") 时会引发以下错误:未知编码:utf8mb4
  • 啊!!这就是我让它工作所需要的。太感谢了! alembic.zzzcomputing.com/en/latest/…
猜你喜欢
  • 2014-12-02
  • 2018-12-15
  • 2018-07-08
  • 1970-01-01
  • 2018-09-09
  • 2015-02-09
  • 1970-01-01
  • 2013-06-16
  • 2017-05-11
相关资源
最近更新 更多