python - SqlAlchemy alembic 迁移文件不使用 env.py 中的连接设置?
问题描述
我有一个适用于名为tenant_schema
. 在我的run_migrations_online
函数中,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
而不是想要的ALTER TABLE other_name.derived_table
解决方案
问题
从关于(强调我的)的SQLAlchemy 文档中:schema_translate_map
该功能仅在模式名称直接从表或序列的名称派生的情况下生效;它不会影响直接传递字符串模式名称的方法
由于所有模式都直接在 alembic 迁移操作中传递,因此schema_translate_map
不考虑。
解决方案
您可能需要的是:
使用 alembic 挂钩来调整模式添加到迁移的方式,使其不是文字字符串,而是在某些全局上下文中查找(例如,渲染
os.environ['TENANT_SCHEMA']
而不是文字字符串'tenant_schema'
)。可能正确的挂钩位置是覆盖渲染函数,请参阅文档中的示例。不幸的是,我无法为此显示任何代码,因为我自己没有尝试过。
或者,您可以尝试注册您的自定义比较器,该比较器将在 alembic 之后运行并且实际上不会比较任何内容,而是将
schema
alembic 生成的操作中的属性替换为自定义字符串子类: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 文档中阅读有关比较器功能的信息。
将该全局上下文中的模式名称设置为运行迁移时所需的值(在此示例中,将
TENANT_SCHEMA
环境变量传递给 alembic 或将其添加到os.environ
您的env.py
.
推荐阅读
- android - Firebase 数据库内容删除
- angular - 使用Angular6中的变量为打印任务动态生成HTML
- google-cloud-platform - ctpu命令搭建TPU测试环境报错
- java - 如何使用 Android Studio 在 Firebase 中检查“用户电子邮件已存在”
- algorithm - 向数组添加或减去随机数以使数字的差值不超过 8 的算法
- c# - 如何在 ASP.NET Core 2.0 的自定义验证属性中进行客户端验证?
- python-3.x - Python - 使用 PIL 库使文本倾斜
- javascript - 当 datePicker 处理程序位于 iframe 中时,KnockoutJS 未捕获 jQuery UI datepicker 更改事件
- phpmyadmin - 禁用对 PHPMyAdmin 4.7.4 的远程访问
- angular - ngFor 中的 Angular 双向绑定