SqlAlchemy Alembic迁移文件不使用env.py中的连接设置吗?

时间:2018-09-05 14:48:37

标签: python orm sqlalchemy alembic

我进行了一个迁移,该迁移适用于名为tenant_schema的通用模式。 在run_migrations_online的{​​{1}}函数中,我为env.py设置了schema_translate_map。

我期望tenant_schema将此迁移操作转换为在所需的架构上运行,但是似乎它试图使用架构sqlalchemy运行sql查询。

任何想法如何解决?

示例

迁移文件中的升级功能:

tenant_schema

2018-09-05_17-28_247f3546088f_add_foo_column.py

def upgrade(): op.add_column('derived_table', sa.Column('foo', sa.BigInteger(), nullable=True), schema='tenant_schema') 函数:

run_migrations_online

env.py

例外(完整的追溯时间太长,没有那么多信息):

schema = 'other_name'  # normally i get the name as an argument from alembic
def run_migrations_online():
    connectable = create_engine(get_url(), echo=True)

    with connectable.connect() as connection:
        # setting up the translation map
        conn = connection.execution_options(schema_translate_map={'tenant_schema': schema})
        context.configure(
            connection=conn,
            target_metadata=target_metadata,
            include_schemas=True,
            version_table_schema=schema,
            include_object=include_object,
        )
        with context.begin_transaction():
            context.run_migrations()

如您所见,它尝试执行sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) schema "tenant_schema" does not exist [SQL: 'ALTER TABLE tenant_schema.derived_table ADD COLUMN foo BIGINT'] (Background on this error at: http://sqlalche.me/e/f405) 而不是所需的ALTER TABLE tenant_schema.derived_table

1 个答案:

答案 0 :(得分:1)

问题

SQLAlchemy docsschema_translate_map(重点是我):

  

该功能仅在模式名称直接从表或序列名称派生的情况下才有效; 它不影响直接传递字符串模式名称的方法

由于所有架构都是在Alembic迁移操作中直接传递的,因此不会考虑schema_translate_map

解决方案

您可能需要的是:

  1. 使用Alembic钩子来调整将模式添加到迁移中的方式,以便它不是文字字符串,而是在某些全局上下文中的查找(例如,渲染os.environ['TENANT_SCHEMA']而不是文字字符串{{1 }})。

    挂钩的正确位置可能是重写渲染功能,请参见docs中的示例。不幸的是,因为我自己没有尝试过,所以我无法显示任何代码。

    或者,您可以尝试注册自定义比较器,该自定义比较器将在alembic之后运行,并且实际上不进行任何比较,但是将用自定义字符串子类替换alembic生成的操作中的'tenant_schema'属性:

    schema

    您可以了解比较器功能in alembic docs

  2. 在该全局上下文中将架构名称设置为运行迁移时所需的值(在本示例中,将from alembic.autogenerate import comparators class FakeSchema(str): def __repr__(self): return "os.environ['TENANT_SCHEMA']" @comparators.dispatch_for('schema') def tweak_schema(autogen_context, upgrade_ops, schemas): for op in upgrade_ops.ops: if getattr(op, 'schema', None) == 'tenant_schema': op.schema = FakeSchema(op.schema) autogen_context.imports.add('import os') # for os.environ 环境变量传递给alembic或将其添加到{ {1}}。