もた日記

くだらないことを真面目にやる

Djangoメモ(13) : extendsとblockでテンプレートの継承

Python 3.6.4 Django 2.0.2

A Complete Beginner's Guide to Djangoのチュートリアルを参考にテンプレートを継承してみる。


親テンプレート作成と継承

テンプレートに共通部分がある場合は共通部分を親テンプレートとして定義し、子テンプレートに個別の処理を記述するのがメンテンナンスしやすい。
最初に親テンプレートとなるtemplates/base.htmlを下記内容で新規作成する。

{% load static %}<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>{% block title %}Django Boards{% endblock %}</title>
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
  </head>
  <body>
    <div class="container">
      <ol class="breadcrumb my-4">
        {% block breadcrumb %}
        {% endblock %}
      </ol>
      {% block content %}
      {% endblock %}
    </div>
  </body>
</html>

{% block %}, {% endblock %}は領域を確保するタグで、子テンプレートでこのblock内のHTMLを置き換えることができる。 {% block title %}Django Boards{% endblock %}のようにデフォルト値を指定することもでき、子テンプレートで何も設定されない場合はこのデフォルト値が使用される。

続いて、親テンプレートを継承するようにtemplates/home.htmltemplates/topics.htmlを編集する。
templates/home.htmlは以下の通り。

{% extends 'base.html' %}

{% block breadcrumb %}
  <li class="breadcrumb-item active">Boards</li>
{% endblock %}

{% block content %}
  <table class="table">
    <thead class="thead-dark">
      <tr>
        <th>Board</th>
        <th>Posts</th>
        <th>Topics</th>
        <th>Last Post</th>
      </tr>
    </thead>
    <tbody>
      {% for board in boards %}
        <tr>
          <td>
            <a href="{% url 'board_topics' board.pk %}">{{ board.name }}</a>
            <small class="text-muted d-block">{{ board.description }}</small>
          </td>
          <td class="align-middle">0</td>
          <td class="align-middle">0</td>
          <td></td>
        </tr>
      {% endfor %}
    </tbody>
  </table>
{% endblock %}

最初の行の{% extends 'base.html' %}タグは親テンプレートとしてbase.htmlを継承することを意味している。
そして{% block breadcrumb %}内の<li class="breadcrumb-item active">Boards</li>が親テンプレートの{% block breadcrumb %}に挿入されることになる。
templates/topics.htmlは以下の通り。

{% extends 'base.html' %}

{% block title %}
  {{ board.name }} - {{ block.super }}
{% endblock %}

{% block breadcrumb %}
  <li class="breadcrumb-item"><a href="{% url 'home' %}">Boards</a></li>
  <li class="breadcrumb-item active">{{ board.name }}</li>
{% endblock %}

{% block content %}
    <!-- just leaving it empty for now. we will add core here soon. -->
{% endblock %}

{% block title %}タグでデフォルト値から変更しているが、{{ block.super }}で親テンプレートのデフォルト値を再利用できる。結果として、board.nameが"Python"の場合は"Python - Django Boards"になる。これでテンプレートの継承は完了。


ナビゲーションバー追加

ナビゲーションバー(BootstrapのNavbarを利用)を追加するためにtemplates/base.htmlを以下のように編集。

{% load static %}<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>{% block title %}Django Boards{% endblock %}</title>
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
  </head>
  <body>

    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
      <div class="container">
        <a class="navbar-brand" href="{% url 'home' %}">Django Boards</a>
      </div>
    </nav>

    <div class="container">
      <ol class="breadcrumb my-4">
        {% block breadcrumb %}
        {% endblock %}
      </ol>
      {% block content %}
      {% endblock %}
    </div>
  </body>
</html>

ページにアクセスするとナビゲーションバーが追加されている。
このように共通で使用する要素を親テンプレートに定義すると便利。

f:id:wonder-wall:20180312225639p:plain

f:id:wonder-wall:20180312225705p:plain


参考:フォント変更

チュートリアルではフォント変更をしているのでナビゲーションバーのロゴ部分(.navbar-brand)のフォントを変更してみる。

fonts.google.com

Google Fontsにアクセスして自分の好きなフォントを選択する。
チュートリアルではPeraltaを使っているがPacificoを使ってみる。

f:id:wonder-wall:20180312231237p:plain

図のように追加方法が表示されるのでtemplates/base.htmlを編集。

  <head>
    <meta charset="utf-8">
    <title>{% block title %}Django Boards{% endblock %}</title>
    <link href="https://fonts.googleapis.com/css?family=Pacifico" rel="stylesheet">
    <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="{% static 'css/app.css' %}">
  </head>

css/app.cssを下記内容で新規作成。

.navbar-brand {
  font-family: 'Pacifico', cursive;
}

これでフォントが変わる。

f:id:wonder-wall:20180312231331p:plain


まとめ

  • テンプレートの共通部分は親テンプレートにまとめる
  • {% extends 'base.html' %}は親テンプレートとしてbase.htmlを継承
  • {% block %}, {% endblock %}で領域を確保し、子テンプレートで該当ブロックを置き換える
  • {% block %}にはデフォルト値を指定することも可能
  • {{ block.super }}で親テンプレートのデフォルト値を参照可能