アプリケーションコンテキストの項目でだいぶコンテキストについてもわかってきました。
コンテキストって、結局、グローバル風にアクセスできるデータをどうやって作るか、みたいなところなのかな
flaskのコンテキストについて、引き続き調べていきたいと思います。今回は、チュートリアルのリクエストコンテキストについて読み進めたところです。大体アプリケーションコンテキストと同じような内容も多かったです^^;
読み進めているチュートリアルページはこちらです。
こんな人の役に立つかも
・PythonでWebアプリケーションを作成したい人
・flaskのチュートリアルを行なっている人
・flaskのコンテキストについて知りたい人
リクエストコンテキストについて
リクエストコンテキストは、リクエストレベルのデータをリクエストの間利用できるようにするものです。リクエストレベルのデータ、は、「request」と「session」というproxy(代わりにアクセスできる変数)のことを指しています。
チュートリアルでのリクエストコンテキストの利用例
チュートリアルで使ってきたrequestとsessionの利用方法をまとめました。大体使い方も似通ってくると思いますので、代表的なパターンは覚えておくと便利かもしれません。
①request
リクエストがPOSTなのかGETなのかを判定
if request.method == 'POST':
フォームに入力されたデータを取得
request.form['username']
cookieにアクセスする
request.cookies.get('username')
②session
flaskのsessionは、cookieで実装されていますので、技術的にはrequestと同じですが、sessionを直接操作できるようにsessionというリクエストコンテキストが準備されています。
セッションをクリア
session.clear()
セッションにuser_id項目(任意の項目名)を追加
session['user_id'] = user['id']
セッションから値を取得(先ほど追加したuser_id項目の値)
session.get('user_id')
コンテキストのライフタイム
アプリケーションコンテキストでも紹介されました。
コンテキストの生成と消滅の順番
コンテキストは次のような順番で生成、消滅をします。(スタックで管理されます。)
①リクエスト処理開始
②アプリケーションコンテキストの作成(スタックへPUSH)
③リクエストコンテキストの作成(スタックへPUSH)
④リクエスト処理終了
⑤リクエストコンテキストの削除(スタックからPOP)
⑥アプリケーションコンテキストの削除(スタックからPOP)
ここまでは、アプリケーションコンテキストの項目でも書いてありました。
コンテキストはスレッドでユニーク
コンテキストは、スレッド毎にユニークで、他のスレッドは他のコンテキストのスタックを持っています。とのことでした。ここの項目で、コンテキストの意味がもう少し理解できた気がします。
Webアプリは、多数のクライアントから多くのリクエストをタイミング不定で受け付けます。しかし、一度に処理するリクエストは1つです。そのため、いくつものリクエストに対してそれぞれのクライアントに対応する「request」や「session」といったいろいろな処理で利用されるグローバルな性質を持つ変数を定義したいです。
そこで、スレッド単位でコンテキストというアプリケーション内のどのメソッドからでも参照できるようなグローバルな性質のデータを保持しつつ、リクエスト単位ではお互いに干渉しないようなデータを実現しているんだなあ、と現段階では理解しています。
(スレッドについて深くわからない場合、実行するプログラムのかたまりのようなイメージで良いと思います。この場合、クライアントのリクエストから発生する一連の処理を1つのスレッドとしているイメージです。)
言葉が小難しくてすみません・・・
リクエスト単位で保持できるようなグローバルなデータが実現できているようなイメージですね
普段、スタンドアロンのアプリ等だと、意識しないような流れですので、理解が難しかったのかと思います。
手動でリクエストコンテキストをPUSH
もちろん、リクエストコンテキストもテスト用プログラムなどで利用するときはコンテキストがスタックにPUSHされている必要があります。
テストプログラムでは、リクエストも意図的に発生させたりしなければいけないので、リクエストコンテキストのproxy(変数って呼ぶとなんだか違う気がするので、翻訳せずにproxyと呼んでいます。)である「request」と「session」にはコンテキストの中でアクセスする必要があります。
test_clientオブジェクトでアクセス
チュートリアルでは、次のようにfixtureでtest_clientをclientとして定義しています。
@pytest.fixture
def client(app):
return app.test_client()
そして、例えば、ログインのテストでは、「with client:」として、GETリクエストを送信することで、sessionにアクセスしています。(クライアントがリクエストを投げてからアクセス)
def test_login(client, auth):
assert client.get('/auth/login').status_code == 200
response = auth.login()
assert response.headers['Location'] == 'http://localhost/'
with client:
client.get('/')
assert session['user_id'] == 1
assert g.user['username'] == 'test'
test_request_contextでアクセス
手動でリクエストコンテキストをPUSHするためには、次のように「test_request_context」も利用できます。この時も、リクエストを投げてから「generate_report」というrequestにアクセスする関数を利用しています。
def generate_report(year):
format = request.args.get('format')
...
with app.test_request_context(
'/make_report/2017', data={'format': 'short'}):
generate_report()
test_とつくように、もうテスト用にリクエストコンテキストを利用するようなパターンが主の利用用途みたいですね。