我进行了一个迁移,该迁移适用于名为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
答案 0 :(得分:1)
从SQLAlchemy docs到schema_translate_map
(重点是我):
该功能仅在模式名称直接从表或序列名称派生的情况下才有效; 它不影响直接传递字符串模式名称的方法
由于所有架构都是在Alembic迁移操作中直接传递的,因此不会考虑schema_translate_map
。
您可能需要的是:
使用Alembic钩子来调整将模式添加到迁移中的方式,以便它不是文字字符串,而是在某些全局上下文中的查找(例如,渲染os.environ['TENANT_SCHEMA']
而不是文字字符串{{1 }})。
挂钩的正确位置可能是重写渲染功能,请参见docs中的示例。不幸的是,因为我自己没有尝试过,所以我无法显示任何代码。
或者,您可以尝试注册自定义比较器,该自定义比较器将在alembic之后运行,并且实际上不进行任何比较,但是将用自定义字符串子类替换alembic生成的操作中的'tenant_schema'
属性:
schema
您可以了解比较器功能in alembic docs。
在该全局上下文中将架构名称设置为运行迁移时所需的值(在本示例中,将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}}。