3

期限切れの sqlalchemy オブジェクトをフラスコ リクエストで処理する方法に頭を悩ませています。私が次のようなことをするとしましょう:

from models import Foo, Bar

@app.route("/page")
def page():
  foos = Foo.query.all()

  for foo in foos:
    b = Bar(foo.data)
    db.session.add(b)

  db.session.commit()

  return render_template('page.html', foos=foos)

そして次にpage.html

{% for foo in foos %}
  {{ foo. name }}
{% endfor %}

コレクションが期限切れとしてsession.commit()マークされているため、SQLAlchemy はテンプレート ループ内の各 foo に対して選択クエリを実行します。を実際に変更するfoos方法がないことがわかっている場合、クエリが実行されないようにする正しい方法は何ですか? 同様に、変更された場合、多くのクエリではなく単一のクエリでデータを更新する正しい方法は何ですか?fooslen(foos)foos

4

2 に答える 2

5

foos を更新する方法がないことがわかっている場合、なぜ を発行する必要があるdb.session.commit()のでしょうか? 場合によっては、何かが更新された場合にのみコミットをトリガーするロジックを入れます。

foos = Foo.query.all()行の下にa を追加するだけdb.session.commit()です。これにより、行ごとに 1 つではなく、すべてのデータに対して 1 つのクエリが起動されます。

あなたが言うように、データをコミットすると期限切れに設定されるため、再クエリが必要になります。おそらく、再クエリするのではなく、セッションを更新することができますsession.refresh(object).

更新: 2 つのセッションの使用

2 番目のセッションを使用して をクエリしFoo、別のセッションで を処理しBarsます。これにより、コミット時に foos が変更されないため、再度実行する必要がなくなります。

大まかな例を次に示します。

from flask.ext.sqlalchemy import Session

@app.route('/example/')
def home():
    session_two = Session(bind=db.engine.connect())
    foos = session_two.query(Foo).all()

    for foo in foos:
        db.session.add(Bar(foo))
    db.session.commit()

    return render_template_string('''
        {% for foo in foos %}
            {{ foo.name }}
        {% endfor %}
    ''', foos=foos)

expire_on_commit=False また、ドキュメントから構成された単一のセッションで処理できるかどうか疑問に思います:

「commit() のもう 1 つの動作は、デフォルトでは、コミットが完了した後に存在するすべてのインスタンスの状態が期限切れになることです。これは、インスタンスが次にアクセスされたときに、属性アクセスまたはクエリ結果セットに存在することによってアクセスされるようにするためです。 、最新の状態を受け取ります。この動作を無効にするには、sessionmaker を expire_on_commit=False で構成します"

Session.expunge の使用

必要に応じてセッションからオブジェクトを削除します

@app.route('/')
def home():
    foos = Foo.query.all()
    for foo in foos:
        db.session.add(Bar(foo))
        db.session.expunge(foo)
    db.session.commit()

    return render_template_string('''
        {% for foo in foos %}
            {{ foo.name }}
        {% endfor %}
    ''', foos=foos)
于 2013-02-15T16:50:42.250 に答える
2

私は少し異なるアプローチをとっていますが、99% の状況ではお勧めしません。(しかし、とにかく共有します)

SqlAlchemy で取得したデータを積極的にキャッシュします。ライブの SqlAlchemy オブジェクトとキャッシュされたデータの間のレベル パリティを装うために、次のことを行います ( https://gist.github.com/jvanasco/01af92e100769d52f7b8を参照)

  • データが Cache に入ったら、それを raw dict に変換します (つまり、すべての sqlalchemy 情報を削除します。テーブルの情報が欲しいだけです)。

  • キャッシュからデータを取得すると、それを「ObjectifiedDict」に変換します。これは、SqlAlchemy オブジェクトと同様に、ドットベースの属性アクセスを提供する dict です。

  • キャッシュからデータをプルするルーチンは、属性を遅延読み込み関数として指定することもできます (これは、キャッシュからデータをプルすると書かれています)。このようにして、「Useraccount」オブジェクトの写真属性を関数として関連付けて、特定の写真をキャッシュから取り出すことができます。

このアプローチでは、私の読み取り専用セクションは、アプリケーションの書き込み可能セクションと同じテンプレートを使用します。唯一の違いは、ビューを見ると、あるセクションのオブジェクトは辞書のバージョンであり、他のセクションは実際の SqlAlchemy であるということです。 .

99% の状況でこれをお勧めしません。しかし、キャッシュされたデータを周りに保持しようとしている 1% の状況では、これが最善の解決策であることがわかりました。

于 2013-02-15T22:36:16.223 に答える