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

タイトル: テンプレート(Template)
SEOタイトル: Django テンプレート完全ガイド — 構文 / 継承 / カスタムタグ

この記事の要点
  • Django テンプレートは HTML の中に 変数 {{ var }}タグ {% ... %}フィルタ {{ var|filter }} を埋め込むテンプレート言語
  • ファイルは app/templates/app/index.html に配置。render(request, "app/index.html", context) で呼ぶ
  • 継承: {% extends "base.html" %} + {% block content %}{% endblock %} で共通レイアウト
  • 制御: {% if %} / {% for %} / {% url "name" %} / {% include "_partial.html" %} / {% static "path" %}
  • カスタムタグ/フィルタは templatetags/ 配下に作成し {% load %} で読み込む

Django テンプレートとは

Django テンプレートは、HTML と テンプレート構文を混在させて、動的な HTML を組み立てる仕組みです。プログラマでなくてもデザイナが触れるよう、Python の構文ではなく独自の DSL を採用しています。

配置と呼び出し

myapp/
├── views.py
├── models.py
└── templates/
    └── myapp/
        ├── base.html
        ├── index.html
        └── detail.html
# myapp/views.py
from django.shortcuts import render

def index(request):
    context = {
        "title": "記事一覧",
        "articles": Article.objects.all(),
        "user_name": "taro",
    }
    return render(request, "myapp/index.html", context)

変数・フィルタ・タグの 3 構文

{# 1. 変数 #}
<h1>{{ title }}</h1>
<p>こんにちは、{{ user_name }} さん</p>

{# 2. フィルタ #}
<p>{{ name|upper }}</p>                    {# 大文字 #}
<p>{{ body|truncatechars:50 }}</p>          {# 50 文字で切る #}
<p>{{ price|floatformat:2 }}</p>            {# 小数 2 桁 #}
<p>{{ created_at|date:"Y-m-d H:i" }}</p>   {# 日付フォーマット #}
<p>{{ html|safe }}</p>                      {# エスケープ無効 (安全な場合のみ) #}
<p>{{ var|default:"未設定" }}</p>           {# null/空のときの代替値 #}

{# 3. タグ #}
{% if articles %}
  <ul>
    {% for a in articles %}
      <li>{{ a.title }}</li>
    {% endfor %}
  </ul>
{% else %}
  <p>記事はありません</p>
{% endif %}

主要フィルタ一覧

フィルタ用途
upper / lower大文字/小文字{{ s|upper }}
title各単語の頭文字を大文字{{ s|title }}
length長さ{{ list|length }}
truncatechars:NN 文字で切る{{ s|truncatechars:50 }}
date:"Y-m-d"日付フォーマット{{ dt|date:"Y-m-d" }}
floatformat:N小数点 N 桁{{ p|floatformat:2 }}
default:"-"null/空時の代替{{ v|default:"-" }}
safeHTML エスケープを無効化{{ html|safe }}
escapeHTML エスケープ{{ s|escape }}
linebreaks改行を
/

{{ s|linebreaks }}
add:N加算{{ n|add:1 }}
join:","配列を結合{{ list|join:"," }}

主要タグ一覧

{# for ループ #}
{% for a in articles %}
  {{ forloop.counter }}: {{ a.title }}
{% empty %}
  記事なし
{% endfor %}

{# if #}
{% if user.is_authenticated %}
  ようこそ {{ user.username }} さん
{% elif user.is_anonymous %}
  ゲストです
{% else %}
  不明
{% endif %}

{# URL 逆引き #}
<a href="{% url 'myapp:detail' article.id %}">詳細</a>

{# static ファイル #}
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<img src="{% static 'img/logo.png' %}" alt="ロゴ">

{# パーシャル取り込み #}
{% include "myapp/_card.html" with article=a %}

{# コメント #}
{# 一行コメント #}
{% comment %}
ブロックコメント
複数行
{% endcomment %}

{# CSRF トークン (フォーム必須) #}
<form method="post">
  {% csrf_token %}
  ...
</form>

{# 変数定義 #}
{% with total=cart.items|length %}
  カート: {{ total }} 件
{% endwith %}

テンプレート継承 (extends + block)

レイアウト共通化の必須テクニックです。

{# templates/base.html #}
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>{% block title %}サイト名{% endblock %}</title>
  {% load static %}
  <link rel="stylesheet" href="{% static 'css/style.css' %}">
  {% block extra_css %}{% endblock %}
</head>
<body>
  <header>{% include "_nav.html" %}</header>
  <main>
    {% block content %}{% endblock %}
  </main>
  <footer>© 2026</footer>
  {% block extra_js %}{% endblock %}
</body>
</html>
{# templates/myapp/index.html #}
{% extends "base.html" %}
{% load static %}

{% block title %}記事一覧 | {{ block.super }}{% endblock %}

{% block extra_css %}
  <link rel="stylesheet" href="{% static 'css/article.css' %}">
{% endblock %}

{% block content %}
  <h1>記事一覧</h1>
  <ul>
    {% for a in articles %}
      <li><a href="{% url 'myapp:detail' a.id %}">{{ a.title }}</a></li>
    {% endfor %}
  </ul>
{% endblock %}

カスタムタグ / カスタムフィルタ

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

@register.filter
def yen(value):
    """1234 → ¥1,234"""
    return f"¥{value:,}"

@register.simple_tag
def current_year():
    from datetime import date
    return date.today().year

@register.inclusion_tag("myapp/_card.html")
def article_card(article):
    return {"article": article}
{# 利用側 #}
{% load myfilters %}

<p>{{ price|yen }}</p>            {# ¥1,234 #}
<p>© {% current_year %} 会社名</p>
{% article_card a %}

セキュリティ — エスケープ

Django テンプレートはデフォルトで HTML エスケープします:

{# context: {"user_input": ""} #}

{{ user_input }}
{# → <script>alert(1)</script> に変換され安全 #}

{{ user_input|safe }}
{# → そのまま