Доступ к моделям в перегонных миграциях

Я использую перегонные миграции для проекта flask+sqlalchemy, и все работает, как и ожидалось, пока я не попытаюсь запросить модели в перегонном кубе.

from models import StoredFile

def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.add_column('stored_file', sa.Column('mimetype', sa.Unicode(length=32))
    for sf in StoredFile.query.all():
        sf.mimetype = guess_type(sf.title)

Приведенный выше код зависает после добавления столбца и никогда не выходит. Я предполагаю, что StoredFile.query пытается использовать другое соединение с базой данных, чем то, которое используется перегонным кубом. (Но почему? Я что-то упустил в env.py?)

Я мог бы решить это с помощью op.get_bind().execute(...), но вопрос в том, как я могу использовать модели непосредственно в перегонном кубе?


person Devi    schedule 09.07.2013    source источник


Ответы (2)


Вы не должны использовать классы из models в своих перегонных миграциях. Если вам нужно использовать классы моделей, вы должны переопределить их в каждом файле миграции, чтобы сделать миграцию автономной. Причина в том, что одной командой можно развернуть несколько миграций, и возможно, что между моментом написания миграции и ее фактическим выполнением в рабочей среде классы моделей были изменены в соответствии с «более поздней» миграцией.

Например, см. этот пример из документации для Операции.execute:

from sqlalchemy.sql import table, column
from sqlalchemy import String
from alembic import op

account = table('account',
    column('name', String)
)
op.execute(
    account.update(). \
        where(account.c.name==op.inline_literal('account 1')). \
        values({'name':op.inline_literal('account 2')})
        )

Совет: вам не нужно включать весь класс модели, а только те его части, которые необходимы для переноса.

person Dag Høidahl    schedule 21.08.2017

У меня такая же проблема. Когда вы используете StoredFile.query, вы используете сеанс, отличный от того, который использует Alembic. Он пытается запросить базу данных, но таблица заблокирована, потому что вы ее изменяете. Таким образом, обновление просто сидит там и ждет вечно, потому что у вас есть две сессии, ожидающие друг друга. Основываясь на ответе @SowingSadness, это сработало для меня:

from models import StoredFile

def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.add_column('stored_file', sa.Column('mimetype', sa.Unicode(length=32))

    connection = op.get_bind()
    SessionMaker = sessionmaker(bind=connection.engine)
    session = SessionMaker(bind=connection)
    for sf in session.query(StoredFile):
        sf.mimetype = guess_type(sf.title)
    session.flush()
    op.other_operations()
person Michael Lenzen    schedule 04.12.2015