【问题标题】:Alembic support for multiple Postgres schemas对多个 Postgres 模式的 Alembic 支持
【发布时间】:2014-02-02 06:10:20
【问题描述】:

如何使用 Alembic 的 --autogenerate 迁移在 SQL Alchemy 模型中未硬编码的多个 Postgres 模式? (SQLAlchemy support of Postgres Schemas 的镜像问题,但对于 Alembic)。

特别是,我们使用 Postgres 模式来分隔共享同一组表的不同客户端。此外,客户端之间还有一个包含共享内容的模式。 SQL Alchemy 模型不了解架构,架构是在运行时使用session.execute("SET search_path TO client1,shared") 设置的。

默认的--autogenerate 根本没有帮助,因为它会检测模型中不存在的多个架构,并最终删除架构并在默认架构中重新创建每个表。

不过,我真的很想使用--autogenerate,并使用适当的管道来正确设置架构。关于 Alembic 的 API 是否/如何做到这一点的任何建议?

【问题讨论】:

标签: python sqlalchemy alembic


【解决方案1】:

issue 409 开始,使用translated schema names 可以最轻松地完成对租户特定模式的升级/降级操作的应用程序,这也是您通常对多租户执行主应用程序的方式。

进入 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()

Above 会将“None”架构名称转换为给定的租户名称。如果应用程序与具有全局表的默认模式共享基于租户的模式,那么您将使用像“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 以便自动生成仅查看代表最新的“样本”模式租户特定架构的版本。

为了设置 env.py 为正确的命令使用正确的系统,可以使用migration_context.get_x_argument() 的用户定义选项来控制行为。

【讨论】:

  • bases.py/models.py 中的类是否有一个名为 'tenant_schema' 的模式?并且 schema_translate_map 会将其转换为 tenant_schema_name ?
【解决方案2】:

这是一个可行的解决方案:https://gist.github.com/nickretallack/bb8ca0e37829b4722dd1

它仍然需要您在每次迁移生成后编辑模式名称,但至少有趣的工作是由 Alembic 完成的。感谢 Michael Bayer 在邮件列表中提供的帮助。

【讨论】:

    【解决方案3】:

    这是一个相当老的问题,但对于遇到同样问题的任何人,我通过在我的 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 配合得很好。

    【讨论】:

    • 你在 bases.py/models.py 的类中放了什么模式名?我的用例和你一样。
    猜你喜欢
    • 2012-03-07
    • 2022-07-23
    • 2020-09-25
    • 2017-03-18
    • 1970-01-01
    • 2022-08-24
    • 2015-08-18
    • 2015-04-05
    相关资源
    最近更新 更多