この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:T
更新日時:2026-06-11 07:12:00

タイトル: テンプレートで利用する共通のcontextを定義する方法
SEOタイトル: Django Context Processor 完全ガイド(全テンプレに共通変数を注入)

この記事の要点
  • Context Processor = 全テンプレートに自動で渡される変数を作る仕組み
  • 実装は def my_processor(request): return {...} という関数を 1 つ書くだけ
  • 登録は settings.py の TEMPLATES → OPTIONS → context_processors に文字列パスで追加
  • 標準で request / user / perms / messages / debug 等のプロセッサが用意されている
  • 典型用途: サイト名 / グローバルメニュー / 通知数 / 環境バッジ / 認証状態

Context Processor とは

Django のテンプレートは、ビューで render(request, 'template.html', context) に渡した辞書 context しか参照できないのが基本です。しかし「ヘッダーに常に表示するサイト名」「全画面共通のお知らせ件数」など、全テンプレに共通で渡したい変数があります。これを毎回ビューで context['site_name'] = ... と書くのは無駄なので、Context Processor という仕組みで一括注入します。

仕組みの概要

[リクエスト]
   ↓
[ビュー関数] → render(request, 'page.html', {'posts': posts})
   ↓
[テンプレートエンジン] が render を解決する直前に
   context_processors を全部実行して、戻り値の辞書を context に merge
   ↓
[最終 context] = {'posts': posts, 'site_name': 'My Blog', 'user': <User>, ...}
   ↓
[テンプレート] で {{ site_name }} {{ user.username }} が使える

標準で用意されている Context Processor

Processorテンプレに渡る変数用途
django.template.context_processors.debugdebug, sql_queriesDEBUG モード判定
django.template.context_processors.requestrequestテンプレで {{ request.path }}
django.contrib.auth.context_processors.authuser, perms認証ユーザ / 権限
django.contrib.messages.context_processors.messagesmessagesフラッシュメッセージ
django.template.context_processors.csrfcsrf_tokenCSRF トークン(標準で自動有効)
django.template.context_processors.i18nLANGUAGES, LANGUAGE_CODE多言語対応
django.template.context_processors.staticSTATIC_URL静的ファイル URL
django.template.context_processors.mediaMEDIA_URLメディア URL

カスタム Context Processor を作る

ステップ 1: 関数を書く

アプリ内に context_processors.py を作成し、request を受け取って辞書を返す関数を定義します:

# blog/context_processors.py
from django.conf import settings

def site_settings(request):
    &quot;&quot;&quot;全テンプレに渡すサイト共通設定&quot;&quot;&quot;
    return {
        'site_name': 'My Blog',
        'site_description': 'Django で作ったブログ',
        'site_url': 'https://example.com',
        'copyright_year': 2026,
        'env': settings.ENV_NAME,
    }


def global_menu(request):
    &quot;&quot;&quot;サイドバー / ヘッダーの共通メニュー&quot;&quot;&quot;
    menu_items = [
        {'name': 'ホーム', 'url': '/'},
        {'name': '記事一覧', 'url': '/blog/'},
        {'name': 'カテゴリ', 'url': '/blog/category/'},
        {'name': 'お問い合わせ', 'url': '/contact/'},
    ]
    return {'global_menu': menu_items}


def notifications(request):
    &quot;&quot;&quot;ログインユーザの未読通知数&quot;&quot;&quot;
    if request.user.is_authenticated:
        unread = request.user.notifications.filter(read_at__isnull=True).count()
    else:
        unread = 0
    return {'unread_notification_count': unread}

ステップ 2: settings.py に登録

# mysite/settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                # 標準
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                # ★ カスタムを追加
                'blog.context_processors.site_settings',
                'blog.context_processors.global_menu',
                'blog.context_processors.notifications',
            ],
        },
    },
]

ステップ 3: テンプレで使う

{# templates/base.html #}
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}{{ site_name }}{% endblock %}</title>
    <meta name="description" content="{{ site_description }}">
</head>
<body class="env-{{ env }}">
    <header>
        <h1>{{ site_name }}</h1>
        <nav>
            {% for item in global_menu %}
                <a href="{{ item.url }}">{{ item.name }}</a>
            {% endfor %}
        </nav>
        {% if user.is_authenticated %}
            <span>{{ user.username }} さん</span>
            <span class="badge">通知 {{ unread_notification_count }}</span>
        {% endif %}
    </header>

    <main>{% block content %}{% endblock %}</main>

    <footer>&copy; {{ copyright_year }} {{ site_name }}</footer>
</body>
</html>

標準 Processor の威力: request

django.template.context_processors.request を入れておくと、全テンプレで {{ request }} が使えます。これは非常に便利:

{# 現在の URL #}
{{ request.path }}

{# ナビゲーションのアクティブ判定 #}
<a href="/blog/" class="{% if request.path == '/blog/' %}active{% endif %}">記事</a>

{# GET パラメータ #}
{{ request.GET.q }}

{# ユーザー(authenticated_user processor 経由でも取れる) #}
{{ request.user.username }}

パフォーマンスの注意

Context Processor は全てのテンプレート描画で毎回実行されるので、重い処理を書くと全画面が遅くなります:

# ❌ 危険: 全画面で SQL を発行する
def heavy_processor(request):
    return {
        'all_categories': Category.objects.all(),       # 毎回 SELECT
        'popular_tags': Tag.objects.annotate(...)[:10], # 集計クエリ
    }

# ✅ 改善: キャッシュ
from django.core.cache import cache

def cached_processor(request):
    categories = cache.get('all_categories')
    if categories is None:
        categories = list(Category.objects.all())
        cache.set('all_categories', categories, 60 * 5)  # 5 分
    return {'all_categories': categories}

# ✅ 改善: 不要なテンプレでは渡さない
# → 該当テンプレでビュー側 context に入れる方が正解の場合も多い

テスト

# tests/test_context_processors.py
from django.test import RequestFactory, TestCase
from blog.context_processors import site_settings, notifications
from django.contrib.auth.models import User

class ContextProcessorTest(TestCase):
    def setUp(self):
        self.factory = RequestFactory()

    def test_site_settings(self):
        request = self.factory.get('/')
        ctx = site_settings(request)
        self.assertEqual(ctx['site_name'], 'My Blog')

    def test_notifications_anonymous(self):
        request = self.factory.get('/')
        request.user = AnonymousUser()
        self.assertEqual(notifications(request)['unread_notification_count'], 0)

FAQ

Q: ビュー側で同名キーを渡したら?
A: ビュー側の値が優先されます(後勝ち)。Context Processor → ビュー → テンプレの順で合成されます。

Q: 関数の戻り値以外、たとえば例外は?
A: Context Processor で例外を投げると、テンプレ描画全体が失敗します。try/except でフェイルセーフ実装を。

Q: クラスベースビューでも使える?
A: もちろん。Context Processor は renderTemplateResponse 経由で発火するので、CBV / FBV を問わず適用されます。