Python | Web フレームワーク:Django のテンプレート

Python
スポンサーリンク

概要(Django のテンプレート=「HTML にデータを流し込む仕組み」)

Django のテンプレートは、

「HTML のひな型(型)をあらかじめ用意しておいて、
ビューから渡されたデータをそこに流し込んで、完成した HTML を作る仕組み」

です。

Python のコードの中に HTML をベタ書きすると、
すぐにぐちゃぐちゃになります。
テンプレートを使うと、

見た目(HTML・レイアウト)はテンプレートファイルにまとめる
中身のデータ(ユーザー名、一覧、メッセージなど)はビューから渡す

という役割分担ができて、コードが一気に整理されます。

Django のテンプレートエンジンは Jinja2 に似た独自方言ですが、
考え方はほぼ同じで、

{{ ... }} で値を埋め込む
{% ... %} で if や for などの制御を書く

というルールさえ押さえれば、すぐに使いこなせます。

「Python の中に HTML を書く」世界がなぜつらいか

文字列で HTML を返すだけだとすぐ限界が来る

まず、テンプレートを使わない場合をイメージしてみます。
ビューの中で直接 HTML を返すコードはこうなります。

from django.http import HttpResponse

def hello(request):
    username = "Taro"
    html = f"""
    <html>
      <head><title>Hello</title></head>
      <body>
        <h1>こんにちは、{username} さん</h1>
      </body>
    </html>
    """
    return HttpResponse(html)
Python

最初は「これで十分じゃん」と感じます。
でも、少しずつ機能が増えると一気に破綻します。

複数ページで同じヘッダやフッタを使い回したくなる
ログイン状態によって表示を変えたくなる
一覧表示や条件分岐が増えて HTML がどんどん長くなる

そのたびに Python のファイルの中で
巨大な文字列を編集することになり、
見た目の修正とロジックの修正がごちゃ混ぜになります。

ここで「見た目は HTML ファイルに分離しよう」という発想が出てきます。
それを支えるのが Django のテンプレートです。

Django テンプレートの基本イメージ

「HTML の中に、あとで埋める“穴”を開けておく」

テンプレートでは、まず普通の HTML ファイルを作ります。
そこに「あとでビューから渡す値」を埋め込む場所を、
{{ 変数名 }} という形で書いておきます。

例えば、templates/hello.html を作ります。

<!DOCTYPE html>
<html>
  <head>
    <title>Hello</title>
  </head>
  <body>
    <h1>こんにちは、{{ username }} さん</h1>
  </body>
</html>

この {{ username }} が「穴」です。
ビューから username という名前で値を渡すと、
ここにその値が差し込まれます。

Django のテンプレートエンジンは、

{{ ... }} を「値を表示する場所」
{% ... %} を「制御構文を書く場所」

として解釈します。

ビュー側では、このテンプレートを「レンダリング」して返します。

ビューからテンプレートを使う基本パターン

render() を使ってテンプレート+コンテキストを返す

Django では、テンプレートを使ったビューはだいたいこう書きます。

from django.shortcuts import render

def hello(request):
    context = {"username": "Taro"}
    return render(request, "hello.html", context)
Python

ここで重要なポイントを整理します。

一つ目。render() は「テンプレートを読み込んで、コンテキスト(データ)を流し込み、HttpResponse を返す」便利関数です。
テンプレート名(”hello.html”)と、テンプレートに渡したい値の辞書(context)を渡します。

二つ目。テンプレートファイルは通常、アプリの templates ディレクトリに置きます。
例えば myapp/templates/hello.html のような構成です。
settings.pyTEMPLATES 設定で、どのディレクトリをテンプレート検索パスにするかを指定します。

三つ目。テンプレートに渡したい値は、
{"キー": 値} の形で辞書に入れます。
テンプレート側では、そのキー名で参照できます。

この例では、context = {"username": "Taro"} としているので、
テンプレート内の {{ username }}"Taro" に置き換わります。

テンプレートの基本文法(変数・for・if)

変数展開:{{ 変数名 }} で値を表示する

テンプレートの一番基本は「変数を表示する」ことです。

ビュー側でこう渡したとします。

def profile(request):
    user = {"name": "Taro", "age": 20}
    return render(request, "profile.html", {"user": user})
Python

テンプレート profile.html ではこう書けます。

<p>名前: {{ user.name }}</p>
<p>年齢: {{ user.age }}</p>

{{ user.name }} のように、ドットで属性やキーにアクセスできます。
辞書でもオブジェクトでも、同じように扱えます。

繰り返し:{% for … %} ~ {% endfor %}

一覧表示をするときは、for 文を使います。

ビュー側:

def item_list(request):
    items = [
        {"name": "Apple", "price": 100},
        {"name": "Banana", "price": 80},
    ]
    return render(request, "items.html", {"items": items})
Python

テンプレート items.html:

<h1>商品一覧</h1>
<ul>
  {% for item in items %}
    <li>{{ item.name }}: {{ item.price }} 円</li>
  {% endfor %}
</ul>

ここでのポイントは、

{% for item in items %} でループ開始
{% endfor %} でループ終了
中では {{ item.name }} のように変数展開

という構造です。

Python の for 文に似ていますが、
テンプレートでは {% %} で囲むことを忘れないでください。

条件分岐:{% if … %} ~ {% endif %}

表示内容を条件によって変えたいときは if を使います。

ビュー側:

def home(request):
    user = {"name": "Taro"}  # ログインしていないときは None にするなど
    return render(request, "home.html", {"user": user})
Python

テンプレート home.html:

<body>
  {% if user %}
    <p>こんにちは、{{ user.name }} さん</p>
  {% else %}
    <p>こんにちは、ゲストさん</p>
  {% endif %}
</body>

{% if 条件 %}
{% else %}
{% endif %}

という形で、かなり Python に近い感覚で書けます。

この「ちょっとした条件分岐」をテンプレート側に寄せることで、
ビューのコードをスリムに保てます。

テンプレート継承(共通レイアウトを一箇所にまとめる)

base.html で「サイト全体の骨組み」を定義する

テンプレートの強力な機能が「継承」です。
全ページ共通のヘッダやフッタ、レイアウトを base.html にまとめておき、
各ページは「中身だけ」差し替える、という構造にできます。

templates/base.html:

<!DOCTYPE html>
<html>
  <head>
    <title>{% block title %}My Site{% endblock %}</title>
  </head>
  <body>
    <header>
      <h1>My Site</h1>
    </header>

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

    <footer>
      <p>&copy; 2025 My Site</p>
    </footer>
  </body>
</html>

ここで {% block title %}{% block content %}
「子テンプレートが中身を差し込む場所」です。

各ページのテンプレートで base.html を継承する

トップページ用のテンプレートを作ります。

templates/index.html:

{% extends "base.html" %}

{% block title %}ホーム{% endblock %}

{% block content %}
  <p>ようこそ、トップページへ。</p>
{% endblock %}

{% extends "base.html" %} で「このテンプレートは base.html を土台にする」と宣言し、
{% block ... %}{% endblock %} で base.html のブロックを上書きします。

結果として、

HTML の骨組み(head, header, footer)は base.html
ページごとの中身(main の中身や title)は index.html

という構造になります。

これにより、

ヘッダやメニューを一箇所で管理できる
ページ追加時は「中身だけ書けばいい」

という、とても保守しやすい状態になります。

テンプレートとビューの役割分担(ここが一番大事)

ビューは「データを集めてテンプレートに渡す人」

Django の設計思想では、

モデル:データの構造と DB 操作
ビュー:リクエストを受けて、必要なデータを集め、どのテンプレートを使うか決める
テンプレート:見た目(HTML)と簡単な表示ロジック

という役割分担になっています。

例えば「本の一覧ページ」を作るとき、
ビューはこうなります。

from django.shortcuts import render
from .models import Book

def book_list(request):
    books = Book.objects.all()
    return render(request, "book_list.html", {"books": books})
Python

テンプレート book_list.html はこうです。

<h1>本の一覧</h1>
<ul>
  {% for book in books %}
    <li>{{ book.title }}</li>
  {% endfor %}
</ul>

ここでの分担は、

ビュー:Book.objects.all() でデータを集める
テンプレート:渡された books をどう表示するかだけ考える

という形です。

テンプレートに「やらせすぎない」ことが大事

テンプレートは便利なので、
頑張ればかなり複雑なロジックも書けてしまいます。

でも、初心者のうちは特に、

テンプレートには「表示に必要な最低限のロジック」だけ
重い計算や複雑な条件分岐はビュー側で済ませておく

という意識を持つと、
コードがぐっと読みやすくなります。

例えば、「価格を 3 桁区切りで表示したい」なら、
ビュー側で "{:,}".format(price) してからテンプレートに渡す、
というのも立派な選択肢です。

慣れてきたら、テンプレートフィルタやカスタムタグで
表示用のロジックをテンプレート側に寄せる、というステップに進めば十分です。

まとめ(Django テンプレートは「HTML と Python をきれいに分けるための土台」)

Django のテンプレートを初心者向けに整理すると、こうなります。

テンプレートは「HTML のひな型」に {{ 変数 }}{% if %} {% for %} を書いておき、ビューから渡されたデータを流し込んで最終的な HTML を作る仕組み。
ビューでは render(request, "template.html", context) と書くだけで、テンプレートにデータを渡して HttpResponse を返せる。テンプレート側では context のキー名で値を参照できる。
{{ ... }} で値を表示し、{% for ... %}{% endfor %}{% if ... %}{% endif %} で一覧表示や条件分岐を表現する。これは「見た目寄りのロジック」としてテンプレートに任せる。
base.html を作って {% extends %}{% block %} を使うと、ヘッダ・フッタなどの共通レイアウトとページごとの中身をきれいに分離できる。
設計の肝は、「データ取得やビジネスロジックはビュー(+モデル)、表示とレイアウトはテンプレート」という役割分担を意識すること。これができると、Django のコードが一気に整理されていく。

タイトルとURLをコピーしました