Django テンプレートの継承で共通レイアウトをまとめる
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 つの仕組みを使い分けることで、保守しやすいテンプレート設計が実現できます。