SqlAlchemy alembic 迁移文件不使用 env.py 中的连接设置?
SqlAlchemy alembic migration files dont use the connection settings in env.py?
我有一个适用于名为 tenant_schema
的通用模式的迁移。
在 env.py
中的 run_migrations_online
函数中,我为 tenant_schema
.
设置了一个 schema_translate_map
我希望 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
而不是所需的 ALTER TABLE other_name.derived_table
问题
来自 SQLAlchemy docs 关于 schema_translate_map
(强调我的):
The feature takes effect only in those cases where the name of the schema is derived directly from that of a Table or Sequence; it does not impact methods where a string schema name is passed directly
由于所有模式都直接在 alembic 迁移操作中传递,因此 schema_translate_map
未被考虑在内。
解决方案
您可能需要的是:
使用 alembic 钩子调整模式添加到迁移的方式,这样它就不是文字字符串,而是在某些全局上下文中进行查找(例如渲染 os.environ['TENANT_SCHEMA']
而不是文字字符串 'tenant_schema'
)。
挂钩的正确位置可能是覆盖渲染函数,请参阅 docs 中的示例。不幸的是,我无法为此显示任何代码,因为我自己还没有尝试过。
或者,您可以尝试注册您的自定义比较器,它会在 alembic 之后 运行 并且实际上不会比较任何东西,但会用自定义字符串替换 alembic 生成的操作中的 schema
属性子类:
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
您可以阅读比较器函数 in alembic docs。
将全局上下文中的架构名称设置为迁移 运行 时所需的值(在此示例中,将 TENANT_SCHEMA
环境变量传递给 alembic 或将其添加到os.environ
在你的 env.py
).
我有一个适用于名为 tenant_schema
的通用模式的迁移。
在 env.py
中的 run_migrations_online
函数中,我为 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
而不是所需的 ALTER TABLE other_name.derived_table
问题
来自 SQLAlchemy docs 关于 schema_translate_map
(强调我的):
The feature takes effect only in those cases where the name of the schema is derived directly from that of a Table or Sequence; it does not impact methods where a string schema name is passed directly
由于所有模式都直接在 alembic 迁移操作中传递,因此 schema_translate_map
未被考虑在内。
解决方案
您可能需要的是:
使用 alembic 钩子调整模式添加到迁移的方式,这样它就不是文字字符串,而是在某些全局上下文中进行查找(例如渲染
os.environ['TENANT_SCHEMA']
而不是文字字符串'tenant_schema'
)。挂钩的正确位置可能是覆盖渲染函数,请参阅 docs 中的示例。不幸的是,我无法为此显示任何代码,因为我自己还没有尝试过。
或者,您可以尝试注册您的自定义比较器,它会在 alembic 之后 运行 并且实际上不会比较任何东西,但会用自定义字符串替换 alembic 生成的操作中的
schema
属性子类: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
您可以阅读比较器函数 in alembic docs。
将全局上下文中的架构名称设置为迁移 运行 时所需的值(在此示例中,将
TENANT_SCHEMA
环境变量传递给 alembic 或将其添加到os.environ
在你的env.py
).