Flask.gはいつ使用する必要がありますか?


173

それg Flask 0.10のリクエストコンテキストからアプリコンテキストに移動するのを見たので、の使用目的について混乱しましたg

私の理解(Flask 0.9の場合)は次のとおりです。

  • g リクエストコンテキストに存在します。つまり、リクエストの開始時に新しく作成され、リクエストが終了するまで利用可能です。
  • g「リクエスト黒板」として使用することを目的としています。リクエストの期間に関連するものを置くことができます(つまり、リクエストの最初にフラグを設定し、最後に、おそらくbefore_request/ after_requestペアからそれを処理します)。
  • request-level-stateの保持に加えてg、リソース管理、つまりデータベース接続の保持などに使用できます。

これらの文のうち、Flask 0.10で正しくなくなった文はどれですか。誰かが、変更の理由を議論しているリソースを私に指摘できますか?Flask 0.10の「要求黒板」として何を使用すればよいですか-独自のアプリ/拡張機能固有のスレッドローカルプロキシを作成し、コンテキストスタックにプッシュする必要がありますbefore_requestか?アプリケーションが(リクエストとは異なり)長く存続し、リソースが解放されない場合、アプリケーションコンテキストでのリソース管理のポイントは何ですか?


私は同意します、それはかなり奇妙な変化です。うまくいけば、mitsuhikoが何らかの種類のリクエストコンテキストオブジェクトを実装gして0.10で置き換えます。そうでなければ、多くのコードがいくつかの不正なバグの開発を開始するように思えます。
Anorov 2013

11
FWIW、Armin Ronacher(Flaskの作者)は、新しいの使用方法に関するコード例を示す「高度なFlaskパターン」の続編をリリースしましたflask.gSpeakerdeck.com/mitsuhiko/advanced-flask-patterns-1
Markus Unterwaditzer

1
また、新しい要求コンテキストはそれだけで通常の使用で罰金を動作するはずですので、新しいアプリケーションのコンテキストを意味します
ロニー

回答:


119

MarkusによってリンクされているAdvanced Flask Patternsはg0.10 での変更点のいくつかを説明しています。

  • g 現在はアプリケーションコンテキストにあります。
  • すべてのリクエストは新しいアプリケーションコンテキストをプッシュし、古いアプリケーションコンテキストをワイプするためg、コードを変更せずにリクエストごとにフラグを設定するために引き続き使用できます。
  • が呼び出された後、 アプリケーションコンテキストがポップさteardown_requestれます。(Arminのプレゼンテーションでは、これはDB接続の作成などがリクエストの環境をセットアップするタスクであり、内部before_requestおよびで処理されるべきではないためですafter_request

リンクしたソースコードapp_ctx is None or app_ctx.app != self.appで、Falseの場合、古いアプリケーションコンテキストが再利用されているようです。アプリケーションコンテキストは「リクエスト間で共有されない」ため、これは正しくないようです...
nalzok

2
プッシュについてapp.app_context()ですか?その場合、app_context()呼び出しごとに新しいアプリケーションコンテキストをインスタンス化することに注意してください。コンテキストを再利用することはありません。
Y4Kman 2017

1
はい、そうですが、の場合app_ctx is not None and app_ctx.app == self.appapp_ctx = self.app.app_context()行は実行されませんself._implicit_app_ctx_stack.append(None)この場合のみ実行されます。
nalzok 2017

1
ああ、ごめんなさい、私は間違って読みました!プロダクション設定では、スレッド(またはグリーンレット)ごとに1つの要求のみが処理されます。1つだけRequestContextが押されるため、1つだけAppContextが押されます。ただし、デバッグモードがオンでリクエストが失敗した場合、Flaskはコンテキストを保存するため、デバッガーで使用できますNoneがに追加されている_app_ctx_stackため、リクエストが破棄されるときに、AppContextまだポップしないようになっています。同じことが、コンテキストを保持するテストクライアントでも発生するため、検査することができます。
theY4Kman 2017

したがって、gのスコープは要求(スレッド)ごとであり、後続の要求で値を保持しません。
変数の

83

このスレッドの情報の補足として:私flask.gも動作が少し混乱しましたが、いくつかの簡単なテストでそれを明確にすることができました。これが私が試したものです:

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

    with app.test_request_context():
        print('in first request context')
        print('g.foo should be abc, is: {0}'.format(g.foo))
        print('setting g.foo to xyz')
        g.foo = 'xyz'
        print('g.foo should be xyz, is: {0}'.format(g.foo))

    print('in app context, after first request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))

    with app.test_request_context():
        print('in second request context')
        print('g.foo should be abc, is: {0}'.format(g.foo))
        print('setting g.foo to pqr')
        g.foo = 'pqr'
        print('g.foo should be pqr, is: {0}'.format(g.foo))

    print('in app context, after second request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))

そして、それはそれが与える出力です:

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be abc, is: abc
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in app context, after first request context
g.foo should be abc, is: xyz  

in second request context
g.foo should be abc, is: xyz
setting g.foo to pqr
g.foo should be pqr, is: pqr  

in app context, after second request context
g.foo should be abc, is: pqr

Y4Kmanが前述したように、「すべてのリクエストは新しいアプリケーションコンテキストをプッシュします」。また、Flaskのドキュメントにあるように、アプリケーションコンテキストは「リクエスト間で共有されません」。今、(私はそれがこれらのステートメントから暗示だと思うが)、明示的に何を述べておらず、どのような私の明確テストが示すように、あなたがすべきことである決して明示的に、一つのアプリケーションのコンテキスト内にネストされた複数の要求コンテキストを作成していないのでflask.g(とコ)doesnの」アプリケーションと要求レベルで異なる状態が独立して存在する、コンテキストの2つの異なる「レベル」で機能する魔法がある。

現実には、「アプリケーションコンテキスト」であるため、潜在的に非常に誤解を招く名前でapp.app_context() ある要求ごとのコンテキスト、とまったく同じ「要求コンテキスト」。「リクエストコンテキストライト」と考えてください。通常はリクエストコンテキストを必要とするいくつかの変数が必要であるが、リクエストオブジェクトにアクセスする必要がない場合にのみ必要です(たとえば、バッチDB操作をシェルスクリプト)。アプリケーションコンテキストを拡張して、複数のリクエストコンテキストを含めると、問題が発生します。したがって、上記の私のテストではなく、代わりに次のようなコードをFlaskのコンテキストで作成する必要があります。

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in first request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to xyz')
    g.foo = 'xyz'
    print('g.foo should be xyz, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in second request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to pqr')
    g.foo = 'pqr'
    print('g.foo should be pqr, is: {0}'.format(g.foo))

期待される結果が得られます。

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be None, is: None
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in second request context
g.foo should be None, is: None
setting g.foo to pqr
g.foo should be pqr, is: pqr

7
最後の段落のために賛成されたため、フラスコのコンテキストを最初に理解するのは非常に混乱しています。名前から、リクエストコンテキストはリクエストごとであり、アプリコンテキストはリクエストの後でさえ存在するか、またはそのライフタイムの影響を受けないという感覚を得ます。
シマナッチ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.