タイトル: Templateの使用準備
SEOタイトル: Django Template 設定と使い方完全ガイド(DIRS / extends / block / フィルター)
| この記事の要点 |
|
Django Template の全体像
Django Template Language (DTL) は Django 標準のテンプレートエンジン。HTML に {% tag %} や {{ variable }} を埋め込み、ビューから渡されたコンテキストで描画します。Jinja2 も切り替え可能ですが、DTL がデフォルトで完備されているので本記事は DTL を扱います。
ステップ 1: settings.py の TEMPLATES 設定
プロジェクト作成時にデフォルトで生成されていますが、DIRS を埋めるのが最初の作業です:
# mysite/settings.py
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'], # ← プロジェクト共通テンプレ
'APP_DIRS': True, # ← 各アプリの templates/ も探索
'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',
],
},
},
]
| 設定キー | 役割 |
|---|---|
| BACKEND | テンプレートエンジン本体(DTL or Jinja2) |
| DIRS | 共通テンプレディレクトリ(リスト順に探索) |
| APP_DIRS | True で <app>/templates/ を自動探索 |
| context_processors | 全テンプレに自動注入する変数群 |
ステップ 2: ディレクトリ構成
mysite/
├── manage.py
├── mysite/
│ ├── settings.py
│ └── urls.py
├── templates/ ← BASE_DIR / 'templates'(共通)
│ ├── base.html
│ └── partials/
│ ├── header.html
│ └── footer.html
└── blog/ ← アプリ
├── views.py
└── templates/ ← APP_DIRS で自動探索
└── blog/ ← ★名前衝突回避のためアプリ名でネスト
├── index.html
└── detail.html
重要: アプリの templates ディレクトリは blog/templates/blog/ のようにアプリ名でネストするのが慣例。複数アプリで index.html が衝突するのを防ぎます。
ステップ 3: ビューからテンプレートを呼ぶ
# blog/views.py
from django.shortcuts import render
def index(request):
context = {
'posts': Post.objects.all(),
'site_name': 'My Blog',
}
return render(request, 'blog/index.html', context)
# ↑ APP_DIRS により blog/templates/blog/index.html を解決
DTL の基本文法
変数表示 {{ ... }}
<p>{{ post.title }}</p>
<p>{{ user.username }}</p>
<p>{{ posts.0.title }}</p> {# リストのインデックス #}
<p>{{ post.created_at|date:"Y-m-d" }}</p> {# フィルター適用 #}
タグ {% ... %}
{% if user.is_authenticated %}
<p>こんにちは {{ user.username }} さん</p>
{% else %}
<a href="{% url 'login' %}">ログイン</a>
{% endif %}
{% for post in posts %}
<li>{{ post.title }} ({{ forloop.counter }}/{{ posts|length }})</li>
{% empty %}
<li>記事はまだありません</li>
{% endfor %}
{% url 'blog:detail' post.pk %} {# URL 解決 #}
{% csrf_token %} {# CSRF トークン #}
{% load humanize %} {# テンプレタグライブラリ読込 #}
主要フィルター一覧
| フィルター | 例 | 結果 |
|---|---|---|
date | {{ d|date:"Y-m-d H:i" }} | 2026-06-10 12:34 |
length | {{ list|length }} | 要素数 |
default | {{ name|default:"匿名" }} | 空なら "匿名" |
truncatechars | {{ body|truncatechars:50 }} | 50文字 + ... |
safe | {{ html|safe }} | エスケープ無効化(★危険、入力検証必須) |
linebreaks | {{ body|linebreaks }} | 改行を / に |
floatformat | {{ price|floatformat:2 }} | 1234.50 |
upper / lower | {{ s|upper }} | 大文字化 |
テンプレート継承 (extends / block)
共通レイアウトを base.html に定義し、各ページで上書きします:
{# templates/base.html #}
{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>{% block title %}{{ site_name }}{% endblock %}</title>
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
{% include 'partials/header.html' %}
<main>
{% block content %}{% endblock %}
</main>
{% include 'partials/footer.html' %}
</body>
</html>{# blog/templates/blog/index.html #}
{% extends 'base.html' %}
{% block title %}記事一覧 | {{ block.super }}{% endblock %}
{% block content %}
<h1>記事一覧</h1>
<ul>
{% for post in posts %}
<li><a href="{% url 'blog:detail' post.pk %}">{{ post.title }}</a></li>
{% endfor %}
</ul>
{% endblock %}
include で部品化
{# 引数渡し #}
{% include 'partials/card.html' with post=post show_author=True %}
{# 親のコンテキスト引き継がない(独立) #}
{% include 'partials/card.html' with post=post only %}
{% load static %} と静的ファイル
{% load static %}
<link rel="stylesheet" href="{% static 'blog/css/post.css' %}">
<img src="{% static 'blog/img/logo.png' %}" alt="logo">
<script src="{% static 'blog/js/main.js' %}"></script># settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static'] # 開発時の追加探索パス
STATIC_ROOT = BASE_DIR / 'staticfiles' # collectstatic の出力先(本番)
テンプレートのキャッシュ(本番)
# settings.py(本番のみ。DEBUG=True ならコメントアウト)
TEMPLATES = [
{
# ...
'APP_DIRS': False, # cached.Loader 使用時は False
'OPTIONS': {
'loaders': [
('django.template.loaders.cached.Loader', [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
]),
],
'context_processors': [...],
},
},
]
FAQ
Q: テンプレートが見つからないと言われる
A: blog/templates/blog/index.html のようにアプリ名でネストしているか確認。また INSTALLED_APPS に登録され APP_DIRS: True である必要があります。
Q: Jinja2 を使いたい
A: TEMPLATES に BACKEND: 'django.template.backends.jinja2.Jinja2' を追加。DTL と並行利用も可。
Q: テンプレートで Python 関数を直接呼びたい
A: 不可(意図的制限)。カスタムテンプレートタグ / フィルターを templatetags/ に作って {% load %} して使います。