Flask の g オブジェクトは、リクエスト中にデータを一時的に保持するための仕組みである。正しく使えばコードの見通しがよくなるが、誤用すると問題を引き起こす。
g の基本
g はアプリケーションコンテキストに紐づいたオブジェクトで、任意の属性を設定できる。
from flask import Flask, g
app = Flask(__name__)
@app.route('/')
def index():
g.user = 'Alice'
return f'Hello, {g.user}'
g のライフサイクル
g はリクエストごとに新しいオブジェクトが生成される。リクエストが終わると破棄される。
@app.route('/first')
def first():
g.value = 100
return 'Set value'
@app.route('/second')
def second():
# 別リクエストなので g.value は存在しない
return str(getattr(g, 'value', 'Not found')) # 'Not found'
典型的なユースケース: データベース接続
リクエスト中に取得したリソースを g に保持し、リクエスト終了時にクリーンアップする。
import sqlite3
from flask import g
def get_db():
if 'db' not in g:
g.db = sqlite3.connect('app.db')
return g.db
@app.teardown_appcontext
def close_db(exception):
db = g.pop('db', None)
if db is not None:
db.close()
@app.route('/users')
def users():
db = get_db()
cursor = db.execute('SELECT * FROM users')
return str(cursor.fetchall())
teardown_appcontext でリクエスト終了時に必ず接続を閉じる。
before_request との組み合わせ
認証済みユーザーを g に設定するパターン。
@app.before_request
def load_user():
user_id = session.get('user_id')
if user_id:
g.user = User.query.get(user_id)
else:
g.user = None
@app.route('/profile')
def profile():
if g.user is None:
return 'Not logged in', 401
return f'Hello, {g.user.name}'
g の誤用パターン
# 誤用 1: g をグローバル変数のように使う
# g はリクエストごとにリセットされることを忘れない
# 誤用 2: g をスレッド間で共有しようとする
def background_task():
print(g.user) # エラー: コンテキスト外
# 誤用 3: g に大量のデータを詰め込む
g.all_users = User.query.all() # メモリを無駄に消費
g vs session
| g | リクエスト内でのみ有効、サーバーサイドに保持 |
| session | リクエストをまたいで有効、クライアントの Cookie に保存 |
一時的な計算結果やリソースは g に、ログイン状態など永続化が必要なものは session に保存する。