前回記事では静的ファイルの利用をしました
アプリケーションコンテキスト と リクエストコンテキスト
Flaskには
・アプリケーションコンテキスト
・リクエストコンテキスト
という二種類のコンテキストがあります
コンテキストとは、プログラムの実行に必要な各種情報のことですが
アプリケーションコンテキスト
アプリケーションコンテキストとは
リクエストの間 アプリレベルのデータを利用できるようにするものです
アプリケーションレベルのデータには current_app と g があります
current_app = アクティブアプリ(実行中のアプリ)のインスタンス
g = リスエストの間だけ利用できるグローバルなテンポラリ(一次)領域
リクエストごとにリセットされる
これまで、app = Flask(name)で取得したappにアクセスすれば
アプリのインスタンスにアクセスできました
pythonのインスタンスは
以下のソースコードなどがイメージしやすいかと思います
class Circle:
def __init__(self, radius):
# インスタンス変数に値を代入
self.radius = radius
# 関数を定義
def area(self):
return radius * radius * 3.14
radius = 10
# インスタンスの生成
circle = Circle(radius)
print("円の半径:", radius)
print("円の面積:", circle.area())
Flask アプリがスケールすると
app = Flask(name)で取得したインスタンスが
お互いが参照しあい
ループが生じる循環参照 が発生しやすくなり
Flask側でエラーが発生します
Flaskはこの問題を
Flaskアプリのインスタンスであるappを直接参照するのではなく
current_app にアクセスすることで解消します
current_app
current_appは、アプリケーションコンテキストからpushされると
スタックへ積まれて どこからでもアクセス出来るようになります
スタック は 一時的にデータを貯めるデータ構造
スタックに
データを積むことをpush
データを取り出すことをpop
といいます
current_appは、アプリケーションコンテキストから
push(データを積む)と
スタック(一時的にデータを貯めるデータ構造)へ積まれて
どこからでもアクセス出来るようになります
アプリケーションコンテキストの確認 app.pyを調整
(通常書かないコード 内部の仕組み理解のため使用)
# flask クラスをimport
from statistics import mean
from flask import Flask, current_app, g, render_template, url_for
# Flask クラスをインスタンス化する
app = Flask(__name__)
# URLと実行する関数をマッピングする
@app.route("/")
def index():
return "Hello, Flask book like CEML"
# ルーティング
@app.route("/hello/<name>", methods=["GET"], endpoint="hello-endpoint")
# endpoint を指定しない場合は 関数名がendpoint 名となる
# 許可するHTTPメソッドをGETとPOSTにする場合
# methods=["GET","POST"]となる
def hello(name):
# python3.6から導入されたf-stringで文字列を定義
return f"Hello world,{name}!!!!!"
def hello_world():
return "Hello world"
# show_name エンドポイントを作成する
@app.route("/name/<name>")
def show_name(name):
# 変数をテンプレートエンジンに渡す
return render_template("index.html", name=name)
with app.test_request_context():
# /
print(url_for("index"))
# /hello/world
print(url_for("hello-endpoint", name="world"))
# /name/ichiro?page=ichiro
print(url_for("show_name", name="ichiro", page="1"))
# ここで呼び出すとエラーになる
# print(current_app)
# アプリケーションコンテキストを取得してスタックへpushする
ctx = app.app_context()
ctx.push()
# current_appにアクセスが可能となる
print(current_app.name)
# >> app.minimalapp.app
# グローバルなテンポラリ領域に値を設定する
g.connetction = "connection"
print(g.connetction)
g
gはリクエストの間だけ利用できる
グローバルなテンポラリ領域ですが
gも同様にアプリケーションコンテキストが
スタックへ積まれると利用可能になります
gの代表的な利用例はデータベースのコネクション(接続)
などで、サンプルではg.connetction に "connection"
という文字列を格納して出力しています
# グローバルなテンポラリ領域に値を設定する
g.connetction = "connection"
print(g.connetction)
このgに設定した値は同一リクエスト間であれば
どこからでもアクセスすることが可能です
リクエストコンテキスト
リクエストコンテキストは リクエストの間
リクエストレベルのデータを利用できるようにするものです
リクエストレベルのデータにはrequest と sesson があります
リスエストコンテキストを手動で取得してpushするには
Flaskについてまとめ5 で記載した
test_request_context関数を使います
test_request_context関数
with app.test_request_context():
# /
print(url_for("index"))
# /hello/world
print(url_for("hello-endpoint", name="world"))
# /name/ichiro?page=ichiro
print(url_for("show_name", name="ichiro", page="1"))
app.pyファイルを調整
# flask クラスをimport
from statistics import mean
from flask import Flask, current_app, g, render_template, request, url_for
# Flask クラスをインスタンス化する
app = Flask(__name__)
# URLと実行する関数をマッピングする
@app.route("/")
def index():
return "Hello, Flask book like CEML"
# ルーティング
@app.route("/hello/<name>", methods=["GET"], endpoint="hello-endpoint")
# endpoint を指定しない場合は 関数名がendpoint 名となる
# 許可するHTTPメソッドをGETとPOSTにする場合
# methods=["GET","POST"]となる
def hello(name):
# python3.6から導入されたf-stringで文字列を定義
return f"Hello world,{name}!!!!!"
def hello_world():
return "Hello world"
# show_name エンドポイントを作成する
@app.route("/name/<name>")
def show_name(name):
# 変数をテンプレートエンジンに渡す
return render_template("index.html", name=name)
with app.test_request_context():
# /
print(url_for("index"))
# /hello/world
print(url_for("hello-endpoint", name="world"))
# /name/ichiro?page=ichiro
print(url_for("show_name", name="ichiro", page="1"))
# ここで呼び出すとエラーになる
# print(current_app)
# アプリケーションコンテキストを取得してスタックへpushする
ctx = app.app_context()
ctx.push()
# current_appにアクセスが可能となる
print(current_app.name)
# >> app.minimalapp.app
# グローバルなテンポラリ領域に値を設定する
g.connetction = "connection"
print(g.connetction)
with app.test_request_context("/users?updated=true"):
# trueが出力される
print(request.args.get("updated"))