Web アプリケーションでは、ヘッダー・フッター・ナビゲーションなどのレイアウトが全ページで共通になることがほとんどです。Django テンプレートの「継承」を使えば、共通部分を 1 か所にまとめ、ページごとに異なる部分だけを差し替えることができます。
ベーステンプレートを作る
まず、全ページの土台となるベーステンプレートを作ります。差し替え可能な領域を {% block %} タグで定義します。
<!-- templates/base.html --> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>{% block title %}My Site{% endblock %}</title> {% block extra_css %}{% endblock %} </head> <body> <header> <nav> <a href="/">ホーム</a> <a href="/articles/">記事一覧</a> </nav> </header> <main> {% block content %}{% endblock %} </main> <footer> <p>© 2025 My Site</p> </footer> {% block extra_js %}{% endblock %} </body> </html>
{% block content %}{% endblock %} のように名前を付けた領域が、子テンプレートで上書きできるポイントになります。ブロックの中にデフォルトの内容を書いておくこともでき、子テンプレートが上書きしなければそのまま表示されます。
子テンプレートで継承する
子テンプレートは {% extends %} でベーステンプレートを指定し、必要なブロックだけを上書きします。
<!-- templates/articles/list.html --> {% extends "base.html" %} {% block title %}記事一覧 | My Site{% endblock %} {% block content %} <h1>記事一覧</h1> <ul> {% for article in articles %} <li>{{ article.title }}</li> {% endfor %} </ul> {% endblock %}
{% extends %} は必ずテンプレートの 1 行目に書かなければなりません。それより前にテキストや HTML があるとエラーになります。
共通レイアウトを定義し、block タグで差し替えポイントを用意する
extends でベースを継承し、必要な block だけを上書きする
block.super で親の内容を活かす
子テンプレートでブロックを上書きすると、ベーステンプレートのデフォルト内容は完全に置き換わります。親の内容を残しつつ追記したい場合は {{ block.super }} を使います。
{% extends "base.html" %}
{% block extra_css %}
{{ block.super }}
<link rel="stylesheet" href="/static/articles/style.css">
{% endblock %}
ベーステンプレートの extra_css ブロックに何か書かれていれば、それを残したまま新しいスタイルシートを追加できます。共通の CSS を維持しながらページ固有の CSS を足すパターンで役立ちます。
多段階の継承
テンプレートの継承は多段階にできます。「サイト全体のベース → セクションごとのベース → 個別ページ」のような構成が典型的です。
<!-- templates/base.html --> <!-- サイト全体の共通レイアウト --> <!-- templates/articles/base.html --> {% extends "base.html" %} {% block content %} <div class="article-layout"> <aside>サイドバー</aside> <div>{% block article_content %}{% endblock %}</div> </div> {% endblock %} <!-- templates/articles/detail.html --> {% extends "articles/base.html" %} {% block article_content %} <h1>{{ article.title }}</h1> <p>{{ article.body }}</p> {% endblock %}
base.html(サイト全体の共通レイアウト)
articles/base.html(記事セクションのレイアウト)
articles/detail.html(個別ページの内容)
階層が深くなりすぎると追いかけにくくなるため、実務では 2〜3 段階に抑えるのが一般的です。
include で部品を切り出す
継承とは別に、テンプレートの一部を別ファイルに切り出して {% include %} で読み込む方法もあります。
<!-- templates/articles/list.html --> {% extends "base.html" %} {% block content %} <h1>記事一覧</h1> {% for article in articles %} {% include "articles/_card.html" %} {% endfor %} {% endblock %}
<!-- templates/articles/_card.html --> <div class="card"> <h2>{{ article.title }}</h2> <p>{{ article.body|truncatechars:80 }}</p> </div>
include は継承関係を持たず、呼び出し元のコンテキスト変数をそのまま引き継ぎます。ファイル名の先頭に _ を付けるのは「単体では使わない部品テンプレートである」ことを示す慣習です。
テンプレートの継承で共通レイアウトを集約し、include で再利用可能な部品を切り出す——この 2 つの仕組みを使い分けることで、保守しやすいテンプレート設計が実現できます。