23

Alemb アップグレードの一環として、いくつかのデータベース データを変更したいと考えています。

移行のアップグレードに任意のコードを追加できると思っていましたが、次のエラーが発生しました。

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

私はこのエラーを本当に理解していません。どうすればこれを修正できますか、またはこのような操作を行うことは不可能ですか?

4

3 に答える 3

18

提供されたコードの抜粋から、何を達成しようとしているのかを正確に理解することは困難です。しかし、私は推測しようとします。したがって、次の回答は私の推測に基づいています。

4 行目 - モジュールから (DBSession、SmsDelivery、SmsMessagePart) をインポートし、アプリケーションで行うようにこれらのオブジェクトを操作しようとしています。

このエラーは、SmsDelivery がマッパー オブジェクトであることを示しているため、何らかのテーブルを指しています。マッパー オブジェクトは、有効な sqlalchemy 接続にバインドする必要があります。

これは、アプリケーション コードで通常行うように、DB オブジェクトの初期化 (接続と、この接続をマッパー オブジェクトにバインドする) をスキップしたことを示しています。

DBSession は SQLAlchemy セッション オブジェクトのように見えます - 接続バインドも必要です。

Alembic はすでに接続の準備ができており、開いています。op.* メソッドで要求している db スキーマを変更するためです。

したがって、この接続を取得する方法があるはずです。

Alembic のマニュアルによると、op.get_bind() は現在の接続バインドを返し
ます。接続されたデータベースとの完全な対話には、コンテキストから利用可能な「バインド」を使用します。

from alembic import op
connection = op.get_bind()

したがって、この接続を使用してクエリを db に実行できます。

PS。テーブル内のデータにいくつかの変更を加えたいと思ったと思います。この変更を 1 つの更新クエリにまとめることができます。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 式言語のチュートリアルで説明されているように、「実行可能」なものはほとんどすべてです。
于 2012-08-16T21:19:00.773 に答える
16

これを行う場合、おそらく次のように、移行で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():
    ...

そうしないと、必然的に、モデルの変更を行ったり、以前の移行が機能しなくなったりする状況に陥ります。

特に、ベース タイプ自体 (app.models.MyType) ではなく Base を拡張する必要があることに注意してください。これは、タイプがどこかでなくなる可能性があり、再び移行が失敗する可能性があるためです。

于 2013-09-18T03:16:37.010 に答える