python - 对 Alembic 升级进行试运行

标签 python sql database-migration alembic

有时 alembic upgrade head可能在运行时对我的生产数据库失败,即使它对我的测试数据库运行良好。例如,迁移可能会添加 NOT NULL约束以前不包含 NULL 的列s 在我的测试环境中,但确实包含 NULL s 在生产中。

在规划部署时,最好能够在运行迁移之前检查它是否能够干净利落地应用。这对于像 MySQL 这样不支持事务性 DDL(在事务中进行模式更改)的数据库来说可能是不可能的,但对于像 PostgreSQL 这样支持事务性 DDL 的数据库来说,原则上应该是可能的; Alembic 可以尝试在事务中执行升级,然后将其回滚。

(一个警告:这是一个不完美的解决方案,因为 PostgreSQL 允许某些约束为 DEFERRED ,这意味着在您提交之前不会检查它们。我想,如果不创建数据库。但是,执行 DDL 和回滚方法总比没有好。)

Alembic 是否支持此类功能?如果没有,是否有一些hacky方法来实现它?

最佳答案

允许这样做的一个简单技巧是将条件回滚注入(inject) run_migrations_online函数在 env.py仅当存在指示我们想要试运行的标志时才会触发。
如果您的已经被修改,请记忆 run_migrations_online 的默认实现由 alembic init 创建的函数看起来像这样:

def run_migrations_online():
    """Run migrations in 'online' mode.

    In this scenario we need to create an Engine
    and associate a connection with the context.

    """
    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()
注意:
  • __enter__ context.begin_transaction()的方法- 我们已经在默认实现中调用了它 - 为我们提供了一个带有 rollback() 的事务对象方法,如果后端使用事务性 DDL,或者如果事务性 ddl 被强制使用 transactional_ddl 标志 , 和
  • 我们的 context对象有一个 get_x_argument 我们可以用来支持将自定义参数传递给 alembic 的方法命令。

  • 因此,通过以下小的更改(除了添加 as transaction 和最后三行之外,下面的所有内容都相同)我们可以拥有我们的试运行功能:
    def run_migrations_online():
        """Run migrations in 'online' mode.
    
        In this scenario we need to create an Engine
        and associate a connection with the context.
    
        """
        connectable = engine_from_config(
            config.get_section(config.config_ini_section),
            prefix="sqlalchemy.",
            poolclass=pool.NullPool,
    
            # ensure the context will create a transaction
            # for backends that dont normally use transactional DDL.
            # note that ROLLBACK will not roll back DDL structures
            # on databases such as MySQL, as well as with SQLite
            # Python driver's default settings
            transactional_ddl=True,
        )
    
        with connectable.connect() as connection:
            context.configure(
                connection=connection, target_metadata=target_metadata
            )
            with context.begin_transaction() as transaction:
                context.run_migrations()
                if 'dry-run' in context.get_x_argument():
                    print('Dry-run succeeded; now rolling back transaction...')
                    transaction.rollback()
    
    现在,要进行试运行,请执行以下操作:
    alembic -x dry-run upgrade head
    
    并进行真正的运行,只需执行以下操作:
    alembic upgrade head
    
    就像之前一样。

    关于python - 对 Alembic 升级进行试运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51556996/

    相关文章:

    sql - Oracle SQl Dev,如何计算两个日期之间的工作日数

    mysql - 从 MySQL 迁移到 DB2 iSeries

    python - 如何修复解决 Homebrew 医生警告的路径

    python - boto3 和 AWS Athena 权限

    python - 为什么 numpy.unique 不能识别多个 numpy.nan 值是相同的?

    sql - UPPER() 和 LOWER() 不需要?

    python - 使用 networkx 寻找弱关系

    c# - 导入 MSSQL 数据库时出现错误 "database compatibility level is not supported."

    node.js - 使用 knexjs 创建角色

    sql - 将带有重复项的 MySQL 表迁移到带有 UNIQUE 约束的另一个表的最佳方法