[解決済み] Flaskのコンテキストスタックの目的は何ですか?
質問
リクエスト/アプリケーションコンテキストがどのように機能するのか、なぜそのように設計されたのかを十分に理解しないまま、しばらく使っています。リクエストやアプリケーションコンテキストに関して、"stack" の目的は何でしょうか?これらは2つの別々のスタックなのか、それとも両方とも1つのスタックの一部なのか? リクエストコンテキストはスタックにプッシュされるのか、それともスタックそのものなのか? 複数のコンテキストを互いにプッシュ/ポップすることができますか? もしそうなら、なぜそうしたいのでしょう?
質問ばかりで申し訳ありませんが、Request ContextとApplication Contextのドキュメントを読んでも、まだ混乱しています。
どのように解決するのですか?
複数のアプリ
アプリケーションコンテキスト(とその目的)は、Flask が複数のアプリケーションを持つことができることに気づくまでは、実に分かりにくいものです。1つの WSGI Python インタプリタから複数の Flask アプリケーションを実行させたい状況を想像してみてください。ここではBlueprintsの話ではなく、全く別のFlaskアプリケーションの話をしています。
のように設定することができます。 Flaskドキュメンテーションのquot;Application Dispatching"のセクション。 の例です。
from werkzeug.wsgi import DispatcherMiddleware
from frontend_app import application as frontend
from backend_app import application as backend
application = DispatcherMiddleware(frontend, {
'/backend': backend
})
フロントエンドとバックエンドの2つの全く異なるFlaskアプリケーションが作成されていることに注意してください。言い換えれば
Flask(...)
アプリケーションのコンストラクタが 2 回呼び出され、Flask アプリケーションのインスタンスが 2 つ作成されています。
コンテクスト
Flask を使っていると、様々な機能にアクセスするためにグローバル変数を使用することになることがよくあります。例えば、次のようなコードがあると思います。
from flask import request
次に、ビューの中で
request
を使用して、現在のリクエストの情報にアクセスします。明らかに
request
は通常のグローバル変数ではなく、実際には
コンテキストローカル
の値です。言い換えれば、舞台裏で何らかのマジックが働いているのです。
request.path
を取得し
path
属性から
request
オブジェクトの結果が異なる。
request.path
.
実際、複数のスレッドでFlaskを実行しても、Flaskは賢いのでリクエストオブジェクトを分離しておくことができます。そうすることで、2つのスレッドが、それぞれ異なるリクエストを処理しながら、同時に
request.path
で、それぞれのリクエストに対して正しい情報を取得します。
まとめる
Flask は同じインタプリタ内で複数のアプリケーションを扱うことができること、そして Flask では "context local" グローバルが使えるので "current" が何であるかを決定するメカニズムが必要であることはすでに見てきたとおりです。
リクエスト
を行うため)。
request.path
).
これらのアイデアをまとめると、Flask は "current" アプリケーションが何であるかを判断する何らかの方法を持たなければならないことも理解できるはずです!
また、以下のようなコードもあるのではないでしょうか。
from flask import url_for
のように
request
の例では
url_for
関数には、現在の環境に依存するロジックがあります。しかし、この場合、どのアプリが現在のアプリとみなされるかにロジックが大きく依存することは明らかです。上記のフロントエンド/バックエンドの例では、"frontend" と "backend" の両方のアプリが "/login" ルートを持つ可能性があるので、以下のようになります。
url_for('/login')
は、ビューがフロントエンドアプリとバックエンドアプリのどちらのリクエストを処理しているかに応じて、異なるものを返す必要があります。
質問にお答えしますと...
<ブロッククオートスタックの目的は何ですか? アプリケーションのコンテキストは?
Request Contextのドキュメントから。
リクエストコンテキストは内部でスタックとして管理されているので は何度もプッシュとポップを繰り返すことができます。これは 内部リダイレクトのようなものです。
つまり、通常、リクエストやアプリケーションのスタックにあるアイテムは0個か1個ですが、それ以上ある可能性もあるのです。
与えられた例は、リクエストが"内部リダイレクト"の結果を返すようにする場合です。ほとんどの場合、ユーザーに対してリダイレクトを発行してリソース B を指し示します。
これらは2つの別々のスタックですか、それとも1つのスタックの一部ですか?
それらは 2つの独立したスタック . しかし、これは実装の詳細です。重要なのはスタックがあることではなく、いつでも "current"アプリやリクエスト(スタックの一番上)を取得できることです。
<ブロッククオートリクエストコンテキストはスタックにプッシュされるのか、それともスタックそのものなのか?
リクエストコンテキストは、リクエストコンテキストスタックの1つのアイテムです。同様に、"アプリコンテキスト"と"アプリコンテキストスタック"も同様です。
<ブロッククオート複数のコンテキストをPush/Popすることは可能ですか?もしそうなら。 なぜそうしたいのでしょうか?
Flaskアプリケーションでは、通常このようなことは行いません。例えば、内部リダイレクトを行う場合です(上記)。しかしその場合でも、結局は Flask に新しいリクエストを処理させることになるでしょうから、Flask があなたのためにすべてのプッシュ/ポッピングを行うことになります。
しかし、スタックを自分で操作したいケースもあります。
リクエストの外側でコードを実行する
典型的な問題として、Flask-SQLAlchemy 拡張を使って、SQL データベースとモデル定義をセットアップする際に、以下のようなコードを使うことがあります...。
app = Flask(__name__)
db = SQLAlchemy() # Initialize the Flask-SQLAlchemy extension object
db.init_app(app)
そして、彼らは
app
と
db
の値は、シェルから実行されるべきスクリプトの中で使用されます。例えば、 "setup_tables.py" スクリプトの場合...
from myapp import app, db
# Set up models
db.create_all()
この場合、Flask-SQLAlchemy 拡張が知っているのは
app
アプリケーションで使用されますが
create_all()
を実行すると、アプリケーションコンテキストが存在しないことを示すエラーがスローされます。このエラーは正当なものです。
create_all
メソッドを使用します。
なぜ、このように
with app.app_context()
の呼び出しは、ビューで同様の関数を実行するときに使用されます。なぜなら、Flask は実際の Web リクエストを処理するときに、すでにアプリケーションコンテキストの管理を代行しているからです。この問題は、ビュー関数(または他のそのようなコールバック)の外側で、例えば、単発のスクリプトでモデルを使用するときにのみ、本当に出てきます。
解決策は、アプリケーションコンテキストを自分でプッシュすることで、これは次のようにして行うことができます。
from myapp import app, db
# Set up models
with app.app_context():
db.create_all()
これは、新しいアプリケーションコンテキストをプッシュします(アプリケーションの
app
複数のアプリケーションが存在する可能性があることを忘れないでください)。
テスト
スタックを操作したいもう一つのケースは、テストのためです。リクエストを処理し、その結果をチェックするユニットテストを作成することができます。
import unittest
from flask import request
class MyTest(unittest.TestCase):
def test_thing(self):
with app.test_request_context('/?next=http://example.com/') as ctx:
# You can now view attributes on request context stack by using `request`.
# Now the request context stack is empty
関連
-
PythonによるLeNetネットワークモデルの学習と予測
-
[解決済み】IndexError: invalid index to scalar variableを修正する方法
-
[解決済み] for'ループでインデックスにアクセスする?
-
[解決済み] リスト内のアイテムのインデックスを検索する
-
[解決済み] Pythonで現在時刻を取得する方法
-
[解決済み] Pythonのリストメソッドであるappendとextendの違いは何ですか?
-
[解決済み] __init__.py は何のためにあるのですか?
-
[解決済み] 自分」という言葉は何のためにあるのか?
-
[解決済み】if __name__ == "__main__": は何をするのでしょうか?
-
[解決済み】__str__と__repr__の違いは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
PythonによるLeNetネットワークモデルの学習と予測
-
ピローによる動的キャプチャ認識のためのPythonサンプルコード
-
Python 人工知能 人間学習 描画 機械学習モデル作成
-
Python jiabaライブラリの使用方法について説明
-
python implement mysql add delete check change サンプルコード
-
pyCaret効率化乗算器 オープンソース ローコード Python機械学習ツール
-
[解決済み】TypeErrorの修正方法。Unicodeオブジェクトは、ハッシュ化する前にエンコードする必要がある?
-
[解決済み】LogisticRegression: Pythonでsklearnを使用して、未知のラベルタイプ: '連続'を使用しています。
-
[解決済み】Python: SyntaxError: キーワードは式になり得ない
-
[解決済み】ValueError: xとyは同じサイズでなければならない