SqlAlchemy alembic миграционные файлы не используют настройки соединения в env.py? - PullRequest
0 голосов
/ 05 сентября 2018

У меня есть миграция, которая работает с общей схемой с именем 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

1 Ответ

0 голосов
/ 17 сентября 2018

Задача

Из документов SQLAlchemy относительно schema_translate_map (выделено мной):

Функция вступает в силу только в тех случаях, когда имя схемы получено непосредственно из имени таблицы или последовательности; не влияет на методы, в которых имя строковой схемы передается напрямую

Так как все схемы передаются непосредственно в операциях миграции alembic, schema_translate_map не учитывается.

Решение

Что вам, вероятно, нужно:

  1. Используйте alembic hooks, чтобы настроить способ добавления схемы в миграцию, чтобы она была не литеральной строкой, а поиском в некотором глобальном контексте (например, рендер 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 .

  2. Установите имя схемы в этом глобальном контексте равным значению, которое вам нужно при запуске миграции (в этом примере передайте переменную окружения TENANT_SCHEMA в alembic или добавьте ее в os.environ в вашем env.py).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...