如何清理不完整的alembic运行

时间:2013-07-27 04:27:12

标签: python sqlalchemy alembic

我正在尝试使用带有MySQL引擎的alembic来执行在线迁移。我发现当我的onupgrade()方法中的操作失败时,我的数据库卡在一个不一致的状态,我不能使用alembic直到我手动清理在onupgrade()失败之前发生的任何操作

示例:

def upgrade():
    op.create_table('sometable',
            Column('id', INTEGER, primary_key=True),
            Column('name', VARCHAR(150), nullable=False, unique=True))
    op.add_column('anothertable' Column('id', INTEGER))
    op.create_table('secondtable')

因此,如果我运行此操作并且op.add_column失败,即使我修复了add_column行,现在“sometable”也存在,因此第一个操作将始终失败。我无法运行我的降级脚本,因为alembic从未更新版本,因为它没有完成升级。

我在想是否有办法强制运行我的ondowngrade(),这可能有用。我必须忽略错误,因为肯定会有一些错误。就像放弃“第二表”一样。但我无论如何都找不到这样做。

任何人都有办法处理这个问题吗?

2 个答案:

答案 0 :(得分:7)

问题不在于alembic,而在于你使用MySQL,它无法回滚DDL语句。

因此,实现它的唯一(丑陋)方法是进行手动异常处理并逆转在此之前成功的操作。

这样的事情(写在我的脑海里,所以这不是最优雅的解决方案,甚至可能有点不对,但我希望你能得到主旨):

def upgrade():
    try:
        op.create_table('sometable',
            Column('id', INTEGER, primary_key=True),
            Column('name', VARCHAR(150), nullable=False, unique=True))
    except:
        try:
            op.drop_table('sometable')
        except:
            pass
        raise

    try:
        op.add_column('anothertable' Column('id', INTEGER))
    except:
        op.drop_table('sometable')
        try:
            op.drop_column('anothertable', 'id')
        except:
            pass
        raise

    try:
        op.create_table('secondtable')
    except:
        op.drop_table('sometable')
        op.drop_column('anothertable', 'id')
        try:
            op.drop_table('secondtable')
        except:
            pass
        raise

答案 1 :(得分:1)

如果您在版本控制中具有要迁移的数据库模型,则可以临时使用它来创建迁移。 (您可能必须清空版本文件夹/将所有内容放在临时目录中)Alembic会将数据库的当前状态与模型进行比较,并为数据库提供迁移命令以达到该状态。在这种情况下,它应该为您提供将数据库恢复到以前状态的说明。您将不得不查看生成的迁移命令,以确保它正是您所需要的,但您不需要自己生成它们。

之后,您可以删除迁移,并回滚到最新的db模型文件。然后你应该回到你开始的那一步