これだけは知っておきたいDjangoテンプレートの基本文法

Djangoには便利な「テンプレート」と呼ばれる機能があります。
この機能を利用することで、webページの重複部分を繰り返して書く必要がなくなり、とても効率的にHTMLの記述を行うことができます。

変数

テンプレートに変数を渡す

テンプレート内で変数を利用するにはpythonプログラムのviewでテンプレートに変数を渡す必要があります。

テンプレートへ変数を渡すには以下の方法を利用します。
views.py

def viewFunction(request):
  template_name = "template.html"
  context = {"variable" : "hello world!"}
  return render(request,template_name,context)

render関数の第三引数にテンプレート内で利用したい変数を入れた辞書を渡します。
この時、辞書の中のキーの値がテンプレート内での変数名になります。

変数の展開

pythonプログラムのviewで渡した変数はDjangoテンプレート内で展開(HTMLの一部に)することができます。
変数の展開は以下の方法で行うことができます。

{{ 変数名 }}

変数名を二重の中カッコで囲います。

実例

前の二つを踏まえて実際にテンプレートに文字列"Hello World!"が代入されたtextという名前の変数を渡してみることをやってみましょう。

まずはviews.pyの中身を確認します。

def viewFunction(request):
  template_name = "template.html"
  template_text = "Hello World!" # <- テンプレートに渡したい文字列
  context = {"text" : template_text} # <- "text"がテンプレート内での変数名
  return render(request,template_name,context) # <-変数の入った辞書を第三引数に渡す

続いて実際に変数を展開するtemplate.htmlです。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>template</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <p>{{ text }}</p>
</body>
</html>

これが実際に展開されると以下のようになります。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>template</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <p>Hello World!</p>
</body>
</html>

変数textが展開されて文字列Hello World!に置き換わっています。

つぎはテンプレートがさらに便利になるテンプレートタグの紹介です。

テンプレートタグ

Djangoのテンプレートには「テンプレートタグ」と呼ばれるプログラミング言語の予約語に相当する機能を持ったものが存在します。

テンプレートタグは以下のような書き方をされます。

{% タグ名 %}

タグ名を{%%}(中カッコとパーセント記号)で囲って記述します。
以下に代表的なものをいくつか紹介します。

条件分岐(if)

他のプログラミング言語でもおなじみのif、条件分岐です。
ifは以下のように利用します。

{% if 条件 %}
  <p>条件は真です</p>
{% endif %}

上記の場合は条件式が真の場合のみ<p>条件は真です</p>がHTML上に展開されます。
Pythonと比較したときの注意点は{% endif %}を利用してifの終了点を示すことがある点です。

Pythonと違いインデントで終了点を表現できないためendifが必要になります。

条件にはpython同様==!=isが利用できます。

また、変数を条件として利用することもできます。

{% if variable == "django" %}
  <p>条件は真です</p>
{% endif %}

複数条件を続けたい場合は以下のように書くことで実現できます。

{% if 条件1 %}
  <p>条件1は真です</p>
{% elif 条件2 %}
  <p>条件2は真です</p>
{% else %}
  <p>条件1も条件2も偽です</p>
{% endif %}

さらにandやor、notを利用することもできます。

{% if 条件 and 条件2 %}
  <p>条件1も条件2も真です</p>
{% else %}
  <p>条件1か条件2が偽です</p>
{% endif %}
{% if 条件1 or 条件2 %}
  <p>条件1か条件2が真です</p>
{% else %}
  <p>条件1も条件2も偽です</p>
{% endif %}
{% if not 条件1 %}
  <p>条件1は偽です</p>
{% else %}
  <p>条件1は真です</p>
{% endif %}

繰り返し(for)

こちらもおなじみ繰り返しのforです。
pythonのforと同様イテレータブルな要素をとることで繰り返し同じパーツを作ることが出来ます。

items[ "hello", "world", "!" ]のリストが入っていることを想定してみましょう。

{% for item in items %}
  <p>{{ item }}</p>
  <hr>
{% endfor %}

上の例が展開されると

  <p>hello</p>
  <hr>
  <p>world</p>
  <hr>
  <p>!</p>
  <hr>

こうなります。

{% for 新しい変数名 in 変数名 %}の文法です。
pythonと同じですね。
新しい変数名を通常の変数と同じように二重の中カッコ({{ }})で展開することができます。

注意する点は、ifと同様に終了点を示す必要があるためendforで終了点を示してあげることです。

forについてもっと詳しく知りたい場合は、以下のページにまとめてありますのでよろしければどうぞ。

[Django]知ってると便利なforで使える小技

挿入(include)

別のテンプレートを挿入します。

各ページに同じパーツ、アイコン画像や外部のjsファイル、cssファイルを配置するときなどに便利です。

一か所を書き換えるだけですべてが書き換わることになるので、一部のページだけ書き換え忘れたり、何度も書き換え直したりしなくてよくなるため積極的に利用しましょう。

{% include "other_template" %}

利用例

一部のページのみjQueryを必要とする例を考えてみましょう。
js_parts.html

<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>

このファイルで他のページのjsファイルの管理を行います。

template1.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>template</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    {% include "js_parts.html" %}
</head>
<body>
    <p>Hello World!</p>
</body>
</html>

これが展開されると

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>template</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
</head>
<body>
    <p>Hello World!</p>
</body>
</html>

こうなります。

次に紹介するextendsblockの組み合わせのほうが比較的汎用性が高いのであまり利用することはないかもしれませんが、覚えておいて損はないはずです。

ブロック化(block)

webサイトには共通するパーツがかなりたくさんあると思います(ヘッダーやフッター、サイドバーなど)。 この共通するパーツを効率よく管理するにはそれぞれをブロック化してしまうことです。
まあ、言ってみればテンプレートのテンプレートみたいなものです。

これには二つのテンプレートタグを利用します。
まずは、それぞれのページで共通する部分だけで構成された骨格となるHTMLファイルを作ります。
base.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<header>
    <p>ヘッダーの要素</p>
</header>

<p>ボディーの要素</p>

<footer>
    <p>フッターの要素</p>
</footer>
</body>
</html>

次に、これに要素を挿入したい部分をブロック化していきます。
base.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>{% block title %}{% endblock %}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<header>
    {% block header %}
    <p>ヘッダーの要素</p>
    {% endblock %}
</header>

{% block body %}
<p>ボディーの要素</p>
{% endblock %}

<footer>
    {% block footer %}
    <p>フッターの要素</p>
    {% endblock %}
</footer>
</body>
</html>

{% block ブロック名 %}{% endblock %}で囲ったところがひとつのブロックになります。

ブロック名は他のものと名前が被らなければなんでもかまいません。

上の例ではtitleheaderbodyfooterという名前のブロックを作りました。

実際にこの骨格を利用するにはextendsというタグを使います。

以下は一例です。

index.html

{% extends "base.html" %}

{% block title %}トップページ{% endblock %}

{% block body %}
<p>トップページです</p>
{% endblock%}

{% extends "骨格になるファイル名" %}とファイルの先頭に記述することでそのファイルに骨格となるファイルを継承させます。

展開されると以下のようになります。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>トップページ</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<header>
    <p>ヘッダーの要素</p>
</header>

<p>トップページです</p>

<footer>
    <p>フッターの要素</p>
</footer>
</body>
</html>

{% block header %}{% block footer %}はindex.htmlで利用されなかったので骨格のbase.htmlのものがそのまま利用されています。

さらにindex.htmlを継承することでさらに具体的なカスタマイズを加えることもできます。

index.htmlに少し手を加えます。

{% extends "base.html" %}

{% block title %}トップページ{% endblock %}

{% block body %}
<p>トップページです</p>

{% block next %}
{% endblock %}

{% endblock%}

bodyブロックの中にnextというブロックを作りました。

next.html

{% extends "index.html" %}

{% block next %}
<p>ネクストページです</p>
{% endblock%}

nextブロックの中に要素を足しました。

next.htmlは以下のように展開されます。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>トップページ</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<header>
    <p>ヘッダーの要素</p>
</header>

<p>トップページです</p>
<p>ネクストページです</p>

<footer>
    <p>フッターの要素</p>
</footer>

</body>
</html>

base.htmlとindex.htmlの両方を継承したので上記のようになりました。

このように継承したファイルをさらに継承することも可能です。

blockextendsをうまく利用することで共通部分を何度も書く必要がなくなるので管理がしやすく、また複雑なHTMLを見やすくすることができます。

デザインを変更するときも、一か所だけ書き換えればよいので、書き換え忘れるページが出ることがなく保守性も上がります。
DRY(Don’t Repeat Yourself)が実現できていいですね。

終わりに

以上、Djangoテンプレートの代表的な機能の紹介でした。