如何使用Alembic的--autogenerate
迁移多个 Postgres模式,这些模式在SQL Alchemy模型中未经过硬编码? (SQLAlchemy support of Postgres Schemas的镜像问题,但对于Alembic而言)。
特别是,我们使用Postgres模式来分离共享同一组表的不同客户端。此外,客户端之间还有一个带有共享内容的模式。 SQL Alchemy模型不了解模式,模式是在运行时使用session.execute("SET search_path TO client1,shared")
设置的。
默认--autogenerate
没有任何帮助,因为它检测到模型中不存在的多个模式,最终删除模式并重新创建默认模式中的每个表。
我真的想使用--autogenerate
,使用正确的管道来正确设置模式。关于Alembic的API是否/如何做到这一点的任何建议?
答案 0 :(得分:2)
来自issue 409,升级/降级操作的特定于租户的模式的应用程序可以使用translated schema names轻松完成,这也是您通常用于多个主应用程序的方式-tenant。
进入env.py:
def run_migrations_online():
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool)
with connectable.connect() as connection:
for tenant_schema_name in all_my_tenant_names:
conn = connection.execution_options(schema_translate_map={None: tenant_schema_name}
logger.info("Migrating tenant schema %s" % tenant_schema_name)
context.configure(
connection=conn,
target_metadata=target_metadata
)
# to do each tenant in its own transaction.
# move this up to do all tenants in one giant transaction
with context.begin_transaction():
context.run_migrations()
上面会将“无”架构名称转换为给定的租户名称。如果应用程序使用具有全局表的默认模式共享基于租户的模式,那么您将使用某些标记,如“tenant_schema”作为符号:
for tenant_schema_name in all_my_tenant_names:
conn = connection.execution_options(schema_translate_map={"tenant_schema": tenant_schema_name}
并且在迁移文件中引用“tenant_schema”,其中实际的特定于租户的模式名称为:
def upgrade():
op.alter_column("some_table", "some_column", <migration options>, schema="tenant_schema")
对于“自动生成”的情况,解决方案@ nick-retallack提供了更多你将在这一端使用的部分,即使用include_schemas,以便autogenerate只查看代表最新的“标本”模式租户特定架构的版本。
为了设置env.py以使用正确的系统来执行正确的命令,可以使用migration_context.get_x_argument()的用户定义选项来控制行为。
答案 1 :(得分:1)
这是一个可行的解决方案:https://gist.github.com/nickretallack/bb8ca0e37829b4722dd1
它仍然需要您在每次迁移生成后编辑模式名称,但至少有趣的工作是由Alembic完成的。感谢Michael Bayer在邮件列表上提供的帮助。
答案 2 :(得分:1)
这是一个非常古老的问题,但对于遇到同样问题的任何人,我在env.py中使用以下内容解决了这个问题:
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
include_schemas=True,
version_table_schema=build # <-- This is the relevant line
)
with context.begin_transaction():
context.run_migrations()
其中build
是一个定义所需模式名称的字符串。我的用例略有不同(多个分布式构建,其中一个数据库包含多个相同的模式),但是我遇到了同样的问题,即alembic无法正确检测我尝试连接的模式。
我使用环境变量来确定正确的构建,因为它与Zappa的效果非常好。