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

タイトル: setting.pyにおけるテンプレートの設定
SEOタイトル: Django settings.py TEMPLATES 設定完全ガイド(DIRS / APP_DIRS / context_processors)

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li><strong>TEMPLATES は配列</strong>: 複数バックエンド(DjangoTemplates / Jinja2)を併用可能</li><li><strong>BACKEND</strong>: <code>django.template.backends.django.DjangoTemplates</code> が標準</li><li><strong>DIRS</strong>: プロジェクト共通テンプレートのディレクトリ。<code>BASE_DIR / "templates"</code></li><li><strong>APP_DIRS=True</strong>: 各アプリの <code>templates/<app>/</code> を自動探索</li><li><strong>OPTIONS.context_processors</strong>: 全テンプレートに自動注入される変数(<code>{{ user }}</code> 等)</li></ul></td></tr></table>
<h2>TEMPLATES の基本構造</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python"># myproject/settings.py
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

TEMPLATES = [
    {
        &apos;BACKEND&apos;: &apos;django.template.backends.django.DjangoTemplates&apos;,
        &apos;DIRS&apos;: [BASE_DIR / &apos;templates&apos;],
        &apos;APP_DIRS&apos;: True,
        &apos;OPTIONS&apos;: {
            &apos;context_processors&apos;: [
                &apos;django.template.context_processors.debug&apos;,
                &apos;django.template.context_processors.request&apos;,
                &apos;django.contrib.auth.context_processors.auth&apos;,
                &apos;django.contrib.messages.context_processors.messages&apos;,
            ],
        },
    },
]</code></pre>
<p>TEMPLATES は<strong>リストオブディクト</strong>です。1 要素 = 1 テンプレートエンジンの設定。複数エンジンを並べて先頭から探索する形になります。</p>

<h2>各キーの意味</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>キー</th><th>意味</th><th>例</th></tr></thead>
<tbody>
<tr><td><code>BACKEND</code></td><td>使用するテンプレートエンジンのクラス</td><td><code>django.template.backends.django.DjangoTemplates</code> / <code>django.template.backends.jinja2.Jinja2</code></td></tr>
<tr><td><code>NAME</code></td><td>このエンジンの識別名(省略時はクラス名から自動)</td><td><code>'django'</code></td></tr>
<tr><td><code>DIRS</code></td><td>テンプレートを探すディレクトリのリスト</td><td><code>[BASE_DIR / 'templates']</code></td></tr>
<tr><td><code>APP_DIRS</code></td><td>各 INSTALLED_APPS の <code>templates/</code> も探すか</td><td><code>True</code></td></tr>
<tr><td><code>OPTIONS</code></td><td>エンジン固有設定</td><td>context_processors, loaders, debug, autoescape ...</td></tr>
</tbody>
</table>

<h2>テンプレート探索順</h2>

<p>Django は次の順でテンプレートを探します:</p>

<ol>
<li><code>DIRS</code> に書かれたディレクトリを順番に</li>
<li><code>APP_DIRS=True</code> なら <code>INSTALLED_APPS</code> 順に各アプリの <code>templates/</code></li>
<li>見つかった最初のものを使う</li>
</ol>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">myproject/
├── templates/             ← DIRS で指定
│   ├── base.html
│   └── home.html
├── polls/
│   └── templates/
│       └── polls/         ← APP_DIRS=True で自動探索
│           ├── index.html
│           └── detail.html
└── blog/
    └── templates/
        └── blog/
            └── post.html</code></pre>
<p><strong>アプリ名のサブディレクトリで包む</strong>のが定石(<code>polls/templates/polls/index.html</code>)。これは複数アプリで同名テンプレートが衝突しないようにするためです。</p>

<h2>DIRS の書き方(Pathlib)</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python">from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent

# 単一ディレクトリ
&apos;DIRS&apos;: [BASE_DIR / &apos;templates&apos;],

# 複数ディレクトリ
&apos;DIRS&apos;: [
    BASE_DIR / &apos;templates&apos;,
    BASE_DIR / &apos;shared_templates&apos;,
    &apos;/var/www/global_templates&apos;,
],

# 旧形式(Django 3.0 以前)
import os
&apos;DIRS&apos;: [os.path.join(BASE_DIR, &apos;templates&apos;)],</code></pre>
<h2>context_processors(全テンプレートに変数注入)</h2>

<p>すべてのテンプレートで自動的に使える変数を提供する関数群です:</p>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e8f5e9"><th>プロセッサ</th><th>提供する変数</th></tr></thead>
<tbody>
<tr><td><code>django.template.context_processors.debug</code></td><td><code>debug</code>, <code>sql_queries</code>(DEBUG=True 時のみ)</td></tr>
<tr><td><code>django.template.context_processors.request</code></td><td><code>request</code>(HttpRequest オブジェクト)</td></tr>
<tr><td><code>django.contrib.auth.context_processors.auth</code></td><td><code>user</code>, <code>perms</code></td></tr>
<tr><td><code>django.contrib.messages.context_processors.messages</code></td><td><code>messages</code></td></tr>
<tr><td><code>django.template.context_processors.media</code></td><td><code>MEDIA_URL</code></td></tr>
<tr><td><code>django.template.context_processors.static</code></td><td><code>STATIC_URL</code></td></tr>
<tr><td><code>django.template.context_processors.csrf</code></td><td><code>csrf_token</code></td></tr>
<tr><td><code>django.template.context_processors.tz</code></td><td><code>TIME_ZONE</code></td></tr>
<tr><td><code>django.template.context_processors.i18n</code></td><td><code>LANGUAGES</code>, <code>LANGUAGE_CODE</code></td></tr>
</tbody>
</table>

<h3>カスタム context_processor を作る</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python"># myproject/context_processors.py
def site_settings(request):
    return {
        &apos;SITE_NAME&apos;: &apos;My Awesome Site&apos;,
        &apos;SUPPORT_EMAIL&apos;: &apos;support@example.com&apos;,
        &apos;UNREAD_COUNT&apos;: request.user.notifications.unread().count() if request.user.is_authenticated else 0,
    }

# settings.py
TEMPLATES = [
    {
        ...
        &apos;OPTIONS&apos;: {
            &apos;context_processors&apos;: [
                ...
                &apos;myproject.context_processors.site_settings&apos;,
            ],
        },
    },
]

# 以後、全テンプレートで {{ SITE_NAME }} が使える</code></pre>
<h2>カスタムタグ・フィルタの登録</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python"># myapp/templatetags/__init__.py(空ファイル必須)

# myapp/templatetags/my_tags.py
from django import template
register = template.Library()

@register.filter
def upper_first(value):
    return value[:1].upper() + value[1:]

@register.simple_tag
def greeting(name):
    return f"Hello, {name}!"</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">{# template.html #}
{% load my_tags %}

{{ name|upper_first }}
{% greeting "Alice" %}</code></pre>
<h2>Django Templates と Jinja2 の併用</h2>

<p>Django 1.8+ から複数バックエンドを登録できます。Jinja2 は速くて柔軟ですが、Django テンプレートが {{ user.is_authenticated }} などフレームワーク統合は強い:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python">TEMPLATES = [
    {
        &apos;BACKEND&apos;: &apos;django.template.backends.jinja2.Jinja2&apos;,
        &apos;DIRS&apos;: [BASE_DIR / &apos;jinja2&apos;],
        &apos;APP_DIRS&apos;: True,
        &apos;OPTIONS&apos;: {
            &apos;environment&apos;: &apos;myproject.jinja2.environment&apos;,
        },
    },
    {
        &apos;BACKEND&apos;: &apos;django.template.backends.django.DjangoTemplates&apos;,
        &apos;DIRS&apos;: [BASE_DIR / &apos;templates&apos;],
        &apos;APP_DIRS&apos;: True,
        &apos;OPTIONS&apos;: {
            &apos;context_processors&apos;: [...],
        },
    },
]

# 探索順は先頭から。Jinja2 の jinja2/ に同名 .html があれば優先</code></pre>
<p>Jinja2 では <code>jinja2/</code> サブディレクトリが標準(Django Templates の <code>templates/</code> と区別するため)。</p>

<h2>OPTIONS の主要設定</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python">TEMPLATES = [
    {
        ...
        &apos;OPTIONS&apos;: {
            &apos;context_processors&apos;: [...],

            # デフォルト True、False で disable
            &apos;debug&apos;: DEBUG,

            # HTML エスケープを autoescape するか(デフォルト True)
            &apos;autoescape&apos;: True,

            # 不明な変数を解決するときの値(デフォルトは空文字)
            &apos;string_if_invalid&apos;: &apos;INVALID: %s&apos; if DEBUG else &apos;&apos;,

            # カスタムローダー(APP_DIRS=False のとき有効)
            &apos;loaders&apos;: [
                (&apos;django.template.loaders.cached.Loader&apos;, [
                    &apos;django.template.loaders.filesystem.Loader&apos;,
                    &apos;django.template.loaders.app_directories.Loader&apos;,
                ]),
            ],

            # カスタムタグライブラリ
            &apos;libraries&apos;: {
                &apos;my_tags&apos;: &apos;myapp.templatetags.my_tags&apos;,
            },

            # 組み込みタグライブラリの追加
            &apos;builtins&apos;: [&apos;myapp.templatetags.my_tags&apos;],
        },
    },
]</code></pre>
<h3>cached.Loader でパフォーマンス</h3>

<p>本番では cached.Loader を使うとテンプレートのパースをキャッシュして高速化。ただし <code>APP_DIRS</code> と<strong>排他</strong>なので明示的に <code>loaders</code> を書く必要があります:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python">TEMPLATES = [
    {
        &apos;BACKEND&apos;: &apos;django.template.backends.django.DjangoTemplates&apos;,
        &apos;DIRS&apos;: [BASE_DIR / &apos;templates&apos;],
        # &apos;APP_DIRS&apos;: True,     # ← コメントアウト
        &apos;OPTIONS&apos;: {
            &apos;context_processors&apos;: [...],
            &apos;loaders&apos;: [
                (&apos;django.template.loaders.cached.Loader&apos;, [
                    &apos;django.template.loaders.filesystem.Loader&apos;,
                    &apos;django.template.loaders.app_directories.Loader&apos;,
                ]),
            ],
        },
    },
]</code></pre>
<h2>テンプレート継承パターン</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">{# templates/base.html #}
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>{% block title %}{{ SITE_NAME }}{% endblock %}</title>
  {% load static %}
  <link rel="stylesheet" href="{% static &apos;css/main.css&apos; %}">
</head>
<body>
  {% include "partials/_header.html" %}

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

  {% include "partials/_footer.html" %}
</body>
</html>

{# templates/polls/index.html #}
{% extends "base.html" %}

{% block title %}投票一覧 | {{ SITE_NAME }}{% endblock %}

{% block content %}
  <h1>投票一覧</h1>
  <ul>
    {% for q in latest_questions %}
      <li>{{ q.question_text }}</li>
    {% endfor %}
  </ul>
{% endblock %}</code></pre>
<h2>Bootstrap / Tailwind 連携</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">{# Bootstrap CDN #}
{% load static %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">

{# django-crispy-forms + crispy-bootstrap5 で美フォーム #}
# pip install django-crispy-forms crispy-bootstrap5

# settings.py
INSTALLED_APPS += [&apos;crispy_forms&apos;, &apos;crispy_bootstrap5&apos;]
CRISPY_ALLOWED_TEMPLATE_PACKS = &apos;bootstrap5&apos;
CRISPY_TEMPLATE_PACK = &apos;bootstrap5&apos;

# template
{% load crispy_forms_tags %}
<form method="post">
  {% csrf_token %}
  {{ form|crispy }}
  <button class="btn btn-primary">Submit</button>
</form></code></pre>
<h2>環境別 設定の切替</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-python"># 本番では cached.Loader、開発では APP_DIRS=True
if DEBUG:
    TEMPLATES[0][&apos;APP_DIRS&apos;] = True
    TEMPLATES[0][&apos;OPTIONS&apos;].pop(&apos;loaders&apos;, None)
else:
    TEMPLATES[0][&apos;APP_DIRS&apos;] = False
    TEMPLATES[0][&apos;OPTIONS&apos;][&apos;loaders&apos;] = [
        (&apos;django.template.loaders.cached.Loader&apos;, [
            &apos;django.template.loaders.filesystem.Loader&apos;,
            &apos;django.template.loaders.app_directories.Loader&apos;,
        ]),
    ]

# string_if_invalid を開発のみ
if DEBUG:
    TEMPLATES[0][&apos;OPTIONS&apos;][&apos;string_if_invalid&apos;] = &apos;INVALID: %s&apos;</code></pre>
<h2>トラブルシューティング</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#fff3e0"><th>症状</th><th>原因</th><th>対処</th></tr></thead>
<tbody>
<tr><td><code>TemplateDoesNotExist: polls/index.html</code></td><td>DIRS / APP_DIRS / アプリ登録漏れ</td><td>探索パスを <code>print(settings.TEMPLATES)</code> 等で確認</td></tr>
<tr><td><code>{{ request.user }}</code> が動かない</td><td>context_processors に request / auth が無い</td><td>2 つ追加</td></tr>
<tr><td><code>{% csrf_token %}</code> でエラー</td><td>context_processors の csrf が必要(標準で入る)</td><td>RequestContext を使う / render() を使う</td></tr>
<tr><td>cached.Loader を有効化したら変更が反映されない</td><td>サーバ再起動が必要</td><td>開発中は APP_DIRS=True、本番のみ cached</td></tr>
<tr><td>テンプレートタグが見つからない</td><td><code>templatetags/__init__.py</code> 無し</td><td>空ファイルでも置く</td></tr>
</tbody>
</table>

<h2>FAQ</h2>

<p><strong>Q: <code>BASE_DIR / 'templates'</code> と <code>os.path.join(BASE_DIR, 'templates')</code> どっちが良い?</strong><br />
A: 新規プロジェクトは Pathlib(前者)。Django 3.1+ で <code>startproject</code> も Pathlib に変わった。可読性も高い。</p>

<p><strong>Q: テンプレートを動的に追加したい</strong><br />
A: <code>DIRS</code> に動的にパスを追加するか、カスタムテンプレートローダーを実装。プラグイン的に登録するなら <code>libraries</code> + <code>builtins</code>。</p>

<p><strong>Q: 1 つのアプリで複数のテンプレートディレクトリを持ちたい</strong><br />
A: アプリ内に <code>templates/<app>/...</code> を作るのが標準。さらに分けたければ DIRS で追加。</p>