Flask のコンテキストを理解しないと起こるエラー

Flask のコンテキストを理解していないと、「RuntimeError: Working outside of application context」や「RuntimeError: Working outside of request context」といったエラーに遭遇する。これらのエラーの原因と対処法を解説する。

よくあるエラー

from flask import Flask, current_app

app = Flask(__name__)

# エラー: アプリケーションコンテキスト外で current_app にアクセス
print(current_app.config['DEBUG'])

このコードを実行すると以下のエラーが発生する。

RuntimeError: Working outside of application context.

コンテキストとは

Flask には2種類のコンテキストがある。

アプリケーションコンテキストcurrent_app, g が利用可能になる
リクエストコンテキストrequest, session が利用可能になる

リクエストが来ると Flask は自動的に両方のコンテキストをプッシュする。しかし、リクエスト外(CLI スクリプト、テスト、バックグラウンドタスクなど)ではコンテキストが存在しない。

解決策 1: with app.app_context()

アプリケーションコンテキストを手動でプッシュする。

from flask import Flask, current_app

app = Flask(__name__)

with app.app_context():
    print(current_app.config['DEBUG'])  # 正常に動作

解決策 2: with app.test_request_context()

リクエストコンテキストも必要な場合はこちらを使う。

with app.test_request_context('/path'):
    print(request.path)  # '/path'
    print(current_app.name)  # 正常に動作

よくある落とし穴: デコレータ内でのアクセス

# 危険: インポート時にコンテキストが存在しない
from flask import current_app

DEBUG = current_app.config['DEBUG']  # エラー

代わりに関数内でアクセスする。

def is_debug():
    return current_app.config['DEBUG']  # リクエスト処理中に呼ばれるなら OK

Celery などの非同期タスク

バックグラウンドタスク内でコンテキストを使うには、明示的にプッシュする。

from celery import Celery

celery = Celery()

@celery.task
def async_task():
    with app.app_context():
        # ここで current_app, g を使える
        db.session.query(User).all()

コンテキストを理解することで、Flask アプリケーションをリクエストハンドラ以外の場面でも正しく動作させられる。