作为alembic升级的一部分修改数据

2024-05-10 12:56:55 发布

您现在位置:Python中文网/ 问答频道 /正文

作为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

我真的不理解这个错误。我怎样才能解决这个问题,或者这样做是不可能的?


Tags: idmessage错误sanotalembicquerysms
3条回答

你还需要导入Base然后

Base.metatada.bind = op.get_bind()

在这之后,你可以像往常一样毫无错误地使用你的模型。

很难理解您从提供的代码摘录中到底想要实现什么。但我会试着猜的。所以下面的答案将基于我的猜测。

第4行-从模块中导入内容(DBSession、SmsDelivery、SmsMessagePart),然后尝试像在应用程序中那样操作这些对象。

错误显示SmsDelivery是一个映射器对象,因此它指向某个表。映射器对象应该绑定到有效的sqlalchemy连接。

它告诉我,您跳过了数据库对象的初始化(连接并将此连接绑定到映射器对象),就像您在应用程序代码中通常做的那样。

DBSession看起来像SQLAlchemy会话对象-它也应该有连接绑定。

Alembic已经准备好并打开了连接-用于更改您正在使用op.*方法请求的数据库架构。

所以应该有办法得到这种联系。

根据Alembic manual op.get_bind()将返回当前连接绑定:
要与连接的数据库进行完全交互,请使用上下文中提供的“绑定”:

from alembic import op
connection = op.get_bind()

因此,您可以使用此连接将查询运行到数据库中。

另外,我假设您想对表中的数据进行一些修改。您可以尝试将此修改表述为一个更新查询。Alembic有特殊的方法来执行这些更改,因此您不需要处理连接。
alembic.operations.Operations.execute

execute(sql, execution_options=None)

使用当前迁移上下文执行给定的SQL。

在SQL脚本上下文中,语句直接发送到输出流。但是,没有返回结果,因为此函数的目标是生成可以在“脱机”模式下运行的更改脚本。

参数:sql–任何合法的SQLAlchemy表达式,包括:

  • 字符串sqlalchemy.sql.expression.text()构造。
  • sqlalchemy.sql.expression.insert()构造。
  • 一个sqlalchemy.sql.expression.update()
  • sqlalchemy.sql.expression.insert(),或
  • sqlalchemy.sql.expression.delete()构造。几乎任何东西 这是SQL表达式语言教程中描述的“可执行文件”。

值得注意的是,如果这样做,您可能希望在迁移过程中冻结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模型更改和以前的迁移不再工作的情况。

特别要注意的是,您希望扩展基类型,而不是基类型本身(app.models.MyType),因为您的类型可能会在某个时候消失,而且您的迁移将再次失败。

相关问题 更多 >