タイトル: テンプレートで利用する共通のcontextを定義する方法
SEOタイトル: Django Context Processor 完全ガイド(全テンプレに共通変数を注入)
| この記事の要点 |
|
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': , ...}
↓
[テンプレート] で {{ site_name }} {{ user.username }} が使える
標準で用意されている Context Processor
| Processor | テンプレに渡る変数 | 用途 |
|---|---|---|
django.template.context_processors.debug | debug, sql_queries | DEBUG モード判定 |
django.template.context_processors.request | request | テンプレで {{ request.path }} 等 |
django.contrib.auth.context_processors.auth | user, perms | 認証ユーザ / 権限 |
django.contrib.messages.context_processors.messages | messages | フラッシュメッセージ |
django.template.context_processors.csrf | csrf_token | CSRF トークン(標準で自動有効) |
django.template.context_processors.i18n | LANGUAGES, LANGUAGE_CODE | 多言語対応 |
django.template.context_processors.static | STATIC_URL | 静的ファイル URL |
django.template.context_processors.media | MEDIA_URL | メディア URL |
カスタム Context Processor を作る
ステップ 1: 関数を書く
アプリ内に context_processors.py を作成し、request を受け取って辞書を返す関数を定義します:
# blog/context_processors.py
from django.conf import settings
def site_settings(request):
"""全テンプレに渡すサイト共通設定"""
return {
'site_name': 'My Blog',
'site_description': 'Django で作ったブログ',
'site_url': 'https://example.com',
'copyright_year': 2026,
'env': settings.ENV_NAME,
}
def global_menu(request):
"""サイドバー / ヘッダーの共通メニュー"""
menu_items = [
{'name': 'ホーム', 'url': '/'},
{'name': '記事一覧', 'url': '/blog/'},
{'name': 'カテゴリ', 'url': '/blog/category/'},
{'name': 'お問い合わせ', 'url': '/contact/'},
]
return {'global_menu': menu_items}
def notifications(request):
"""ログインユーザの未読通知数"""
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 #}
{% block title %}{{ site_name }}{% endblock %}
{{ site_name }}
{% if user.is_authenticated %}
{{ user.username }} さん
通知 {{ unread_notification_count }}
{% endif %}
{% block content %}{% endblock %}
標準 Processor の威力: request
django.template.context_processors.request を入れておくと、全テンプレで {{ request }} が使えます。これは非常に便利:
{# 現在の URL #}
{{ request.path }}
{# ナビゲーションのアクティブ判定 #}
記事
{# 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 は render や TemplateResponse 経由で発火するので、CBV / FBV を問わず適用されます。