Подтвердить что ты не робот

Изменение данных как часть обновления alembic

Я хотел бы изменить некоторые данные базы данных как часть обновления alembic.

Я думал, что могу просто добавить какой-либо код в обновление моей миграции, но следующее не удается:

def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.add_column('smsdelivery', sa.Column('sms_message_part_id', sa.Integer(), sa.ForeignKey('smsmessagepart.id'), nullable=True))
    ### end Alembic commands ###

    from volunteer.models import DBSession, SmsDelivery, SmsMessagePart

    for sms_delivery in DBSession.query(SmsDelivery).all():
        message_part = DBSession.query(SmsMessagePart).filter(SmsMessagePart.message_id == sms_delivery.message_id).first()
        if message_part is not None:
            sms_delivery.sms_message_part = message_part

со следующей ошибкой:

sqlalchemy.exc.UnboundExecutionError: Could not locate a bind configured on mapper Mapper|SmsDelivery|smsdelivery, SQL expression or this Session

Я не понимаю эту ошибку. Как я могу исправить это или делать такие операции не так?

4b9b3361

Ответ 1

Трудно понять, чего именно вы пытаетесь достичь из выдержки из вашего кода. Но я постараюсь угадать. Поэтому следующий ответ будет основан на моей догадке.

Строка 4 - вы импортируете вещи (DBSession, SmsDelivery, SmsMessagePart), формируя свои модули, а затем вы пытаетесь работать с такими объектами, как в своем приложении.

Ошибка показывает, что SmsDelivery является объектом mapper, поэтому он указывает на некоторую таблицу. объекты mapper должны привязываться к действительному соединению sqlalchemy.

Что говорит мне, что вы пропустили инициализацию объектов БД (соединение и привязку этого соединения к объектам mapper), как вы обычно делаете в своем коде приложения.

DBSession выглядит как объект сеанса SQLAlchemy - он должен также связывать соединение.

У Alembic уже есть соединение готово и открыто - для внесения изменений в схему db, запрашиваемых с помощью методов op. *.

Итак, должен быть способ получить это соединение.

В соответствии с руководством Alembic op.get_bind() вернет текущую привязку соединения:
Для полного взаимодействия с подключенной базой данных используйте "привязку", доступную из контекста:

from alembic import op
connection = op.get_bind()

Таким образом, вы можете использовать это соединение для запуска своих запросов в db.

PS. Я предполагаю, что вы хотели бы внести некоторые изменения в данные в своей таблице. Вы можете попытаться сформулировать эту модификацию в один запрос на обновление. У Alembic есть специальный метод для выполнения таких изменений - так что вам не нужно иметь дело с подключением.
alembic.operations.Operations.execute

execute(sql, execution_options=None)

Выполните данный SQL, используя текущий контекст миграции.

В контексте SQL script оператор выдается непосредственно в выходной поток. Однако результата возврата нет, поскольку эта функция ориентирована на создание изменения script, которое может работать в автономном режиме.

Параметры: sql - Любое юридическое выражение SQLAlchemy, включая:

  • Строка: sqlalchemy.sql.expression.text().
  • Конструкция sqlalchemy.sql.expression.insert().
  • a sqlalchemy.sql.expression.update(),
  • sqlalchemy.sql.expression.insert() или
  • sqlalchemy.sql.expression.delete(). Довольно многое thats "исполняемый файл", как описано в учебнике Language Expression Language.

Ответ 2

Стоит отметить, что если вы это сделаете, вы, вероятно, захотите заморозить копию своей модели orm внутри миграции, например:

class MyType(Base):
  __tablename__ = 'existing_table'
  __table_args__ = {'extend_existing': True}
  id = Column(Integer, ...)
  ..

def upgrade():
  Base.metadata.bind = op.get_bind()

  for item in Session.query(MyType).all():
    ...

В противном случае вы неизбежно окажетесь в ситуации, когда вы изменили модель модели orm, и предыдущие миграции больше не работают.

В частности, обратите внимание, что вы хотите расширить Base, а не базовый тип (app.models.MyType), потому что ваш тип может исчезнуть как некоторая точка, и еще раз ваши миграции не удастся.

Ответ 3

Вам нужно также импортировать Base, а затем

Base.metatada.bind = op.get_bind()

и после этого вы можете использовать свои модели, как всегда, без ошибок.