Django入門ノート その4

テンプレートの基本

あらかじめ作成しておいたひな型にデータを投入してHTML等の文字列をつくるテンプレートの基本について勉強です。

まずは単純にテンプレート用の文字列からテンプレートをつくるパターン。
テンプレート文字列をdjango.templateモジュールのTemplateクラスに渡してテンプレートオブジェクトを生成する。データの投入はdjango.templateモジュールのContextクラスでコンテキストオブジェクトを生成し、updateメソッドで内容を追加する。今回は辞書を渡します。 最後にテンプレートオブジェクトのrenderメソッドにコンテキストを渡して呼び出すと最終的な出力文字列が生成される。
test_template.py

#! /usr/bin/env python

from django.http import HttpResponse
from django.template import Template, Context

test_template_string = """
<html>
<body>
<table>
<tr><td>Key</td><td>Value</td></tr>
{% for item in dic.items %}
<tr>
<td>{{ item.0 }}</td><td>{{ item.1 }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
"""
def test_template(request):
    template = Template(test_template_string)
    dic = {"year":2011, "month":12, "day":29}
    context = Context()
    context.update({"dic":dic})
    return HttpResponse(template.render(context))

テンプレート文字列内の{{ ... }}や{% ... %}で囲まれた部分はDjangoのテンプレート言語で記述されたテンプレート命令というものとのこと。前者をテンプレート変数、後者をテンプレートタグ({% for ... %} ... {% endfor %}のようにセットになってるものはブロックタグ)と呼ぶとのこと。テンプレート変数は、出力時に変数の内容で置き換えられ、テンプレートタグはその場所でなんらかの操作を行って、その結果でタグが置き換えられる。今回は{% for ... %} ... {% endfor %}のブロックでループを組んでいる。タグの中ではメソッド呼び出しの()が不要なのも注意点。urls.pyで作成したビューをセットしてアクセスすると辞書dicのキーと値が一覧で表示される。

前の例だと特定のビューとテンプレートが結びついてしまうため実用的ではないので、テンプレートをファイルシステムからロードする方法を続いて勉強します。ファイルシステムからロードすることでページテンプレートの設計とビューの設計を分離することが可能になるとのこと。

まずはテンプレートファイルを入れるディレクトリを作成します。

$ mkdir templates

テンプレート用ディレクトリを作成したらsettings.pyのTEMPLATE_DIRSに絶対パスで登録しておく。
前の例のテンプレート文字列の内容をTEMPLATE_DIRS下のload_template_test.htmlに保存します。
テンプレートのロードにはdjango.templateモジュールのloderオブジェクトを使うとのこと。loderオブジェクトにはget_templateメソッドがあり、テンプレートのパスをTEMPLATE_DIRSからの相対パスで指定すると、テンプレートファイルを探し出してTemplateクラスに渡し、テンプレートオブジェクトを生成して返してくれる。
load_template.py

#! /usr/bin/env python

from django.http import HttpResponse
from django.template import Context, loader

def load_template_test(request):
    dic = {"year":2011, "month":12, "day":29}
    context = Context()
    context.update({"dic":dic})
    template = loader.get_template('load_template_test.html')
    return HttpResponse(template.render(context))

urls.pyで作成したビューをセットしてアクセスすると先の例と同様に辞書dicのキーと値が一覧で表示される。

テンプレートは継承による再利用と拡張が可能とのことでやってみます。
まずは親テンプレートbase.htmlで{% block ... %}タグを使い子テンプレートでカスタマイズ可能なブロックを作成しておく。

base.html

<html>
  <head>
    <title>{{ title }}</title>
	{% block head_extra %}
	{% endblock %}
  </head>
  <body>
    {% block body %}
	  {{ content }}
    {% endblock %}
  </body>
</html>

一方の子テンプレートextend.htmlでは親テンプレートの名前を指定して{% extends ... %}を呼び出し、親テンプレートのブロックのうち、子テンプレートでカスタマイズしたい部分を{% block %}で定義する。これをブロックのオーバーライドと呼ぶとのこと。

extend.html

{% extends "base.html" %}
{% block head_extra %}
  <meta http-equiv="content-type: text/html; charset=UTF8" />
{% endblock %}
{% block body %}
  <h1>{{ title }}</h1>
  <hr />
  {{ content }}
  <hr />
{% endblock %}

子テンプレートを使用するビューを書いてみます。

extend_template_test.py

#! /usr/bin/env python

from django.http import HttpResponse
from django.template import Context, loader

def extend_template(request):
    context = Context()
    dic = {'title':u'継承によるテンプレートの再利用と拡張', 'content':u'本文'}
    context.update(dic)
    template = loader.get_template('extend.html')
    return HttpResponse(template.render(context))

urls.pyで作成したビューをセットしてアクセスすると子テンプレートでオーバーライドしたブロックの内容が置き換わっている。

ちなみにテンプレートのブロックは何重でもネスト可能で、子テンプレートではどのレベルのブロックをオーバーライドしてもよいらしい。