このページでは、Django におけるテンプレート(Template)について解説していきます。
Django で開発するウェブアプリの基本構造は MTV モデルとなっています。
前回、下記ページで V の部分のビューに関して解説を行いました。

今回は、T の部分のテンプレートについて解説していきます。テンプレートは MTV モデルの1部分であり、Django でのウェブアプリ開発において重要な存在となります。
是非、このページを読み進めていただき、テンプレートがどんなものであるかを理解していっていただければと思います!
Contents
テンプレートの基本
では、テンプレートについて解説していきます。
テンプレート
テンプレートとは、ページの雛形を提供するアプリの構成部分となります。
このテンプレートファイルを利用することで、ウェブアプリで無数のページ表示を行うことが可能になります。
例えば、ウェブアプリでログインユーザーの情報を表示する『マイページ』を実現することを考えてみましょう!
このマイページは、当然ユーザーによって表示される情報が異なることになります。例えば、このページで『ユーザー名』『アイコン画像』『自己紹介文』が表示されるとすると、これらの情報はユーザーによって異なるはずです。
したがって、このようなマイページの表示を実現するためには、ユーザーの数だけ HTML を用意し、ログイン中のユーザーに応じた HTML をウェブブラウザ等のクライアントに返却するようにする必要があります。
この HTML の用意の仕方には様々な方法があります。最も単純な方法は、ユーザーごとに HTML を事前に作成しておく方法になると思います。ただ、これは単純ですが大変で、ユーザーの数の分だけ HTML を作成する必要があります。例えばウェブアプリのユーザーが一万人いれば、一万個の HTML を作成しておく必要があります…。
他の方法としては、ページの雛形部分だけを事前に作成しておき、ユーザーからマイページの表示のリクエストを受けた際に、そのユーザーの情報を雛形に埋め込んで HTML を用意する方法になります。これが、このページの主題となるテンプレートの考え方となります。
先程のマイページに注目してみれば、これらのページはユーザー毎に『ユーザー名』『アイコン画像』『自己紹介文』の内容は異なるものの、それ以外の部分は同じです。このように、同じ種類のページであれば、ページの雛形としては同じものが利用できるケースが多いです。
したがって、ページの雛形部分だけを事前に作成しておき、ユーザーからマイページの表示のリクエストを受けた際にユーザーに応じた『ユーザー名』『アイコン画像』『自己紹介文』を雛形に埋め込んで HTML を生成して返却するようにすれば、1つの雛形から全ユーザーのマイページの表示を実現することができるようになります。
このように、基本的にウェブアプリで表示するページは雛形と動的に変更が必要な部分(動的な部分)の2種類から構成されています。
したがって、雛形となる部分のみを事前に作成しておき、ウェブアプリがリクエストを受け取った時に、その雛形に対してリクエストに応じた情報を動的に埋め込んで HTML を生成するようにすれば、1つの雛形からリクエストに応じたページ表示を実現することができるようになります。
このような、部分的に表示結果を動的に変更可能な雛形を提供することがテンプレートの役割となります。このような雛形はテンプレートファイルと呼ばれます。また、テンプレートファイルからの HTML の生成は、次に説明する render
関数によって行われます。また、動的に変更可能な部分に埋め込むデータはコンテキストと呼ばれるデータによって提供されます。これに関しては後述の コンテキスト で説明します。
また、1つのテンプレートファイルから生成可能な HTML の雛形は全て共通となります。そのため、異なる雛形のページを表示できるようにしたいのであれば、別途テンプレートファイルを作成しておく必要があります。そのため、基本的にウェブアプリを実現する上で必要になるテンプレートファイルは複数になります。
大体テンプレートの意味合いに関しては理解していただけたのではないでしょうか?
次は、ここまでの解説の中にも登場してきた render
関数やコンテキストの意味合いについて説明し、その後テンプレートファイルの作り方について解説していきたいと思います。
スポンサーリンク
render
関数
ということで、まずはテンプレートを利用する上で重要となる render
関数について解説していきます。
render
関数とは
render
関数は、先程説明したテンプレートファイルから HTML を生成する関数になります。より正確に言えば、テンプレートファイルから HTML を生成し、さらにその HTML をボディとするレスポンス(HttpResponse
のインスタンス)を返却する関数となります。
この render
関数は Django フレームワークから提供される関数で、django.shortcuts
で定義されています。さらに、この render
関数はビューから実行される関数となります。
render
関数の引数
render
関数の引数は下記のように定義されています。
render(request, template_name, context=None, content_type=None, status=None, using=None)
引数が多いですが、指定が必須なのは request
・template_name
の2つになります。ただし、コンテキスト で説明するように、動的に HTML の一部を変化させるためには context
の指定も必要となります。
まず、request
引数には HttpRequest
のインスタンスを指定する必要があります。この引数にはビューが Django フレームワークから受け取った引数 request
をそのまま指定してやれば良いです。
また、template_name
引数にはテンプレートファイルのパスを指定します。
このように引数を指定してビューが render
関数を実行すれば、template_name
引数に指定されたテンプレートファイルの記述に基づいて HTML が生成され、その生成結果をボディとするレスポンスを返却値として取得することができます。
前述の通り、テンプレートファイルは複数用意されることが多いため、リクエストに応じて適切なテンプレートファイルを選択し、そのファイルのパスを render
関数の template_name
引数に指定する必要があります。
コンテキスト
また、render
関数には引数 context
にコンテキストを指定して渡すことも可能です。
コンテキストとは
このコンテキストは辞書形式のデータであり、キー
と 値
を各要素に持つデータとなります。
詳細に関しては後述で解説しますが、テンプレートファイルからは変数を参照することが可能です。この参照される変数の値を提供するのがコンテキストになります。
コンテキストと render
関数
例えば、テンプレートファイルに {{ name }}
と記述している場合、render
関数で HTML が生成される際に {{ name }}
部分が name
変数の値に置き換えられることになります。
変数の値は render
関数の中でコンテキストから取得されます。より具体的には、テンプレートファイルに {{ name }}
が記述されている場合、render
関数の context
に指定された辞書データにおける 'name'
キーの値が取得されることになります。そして、HTML 生成時に {{ name }}
部分が 'name'
キーの値に置き換えられることになります。
例えば、下記のような辞書データを render
関数の context
引数に指定した場合、{{ name }}
部分は YamadaHanako
に置き換えられることになります。
context = {
'name' : 'YamadaHanako',
}
つまり、テンプレートファイルから参照される変数 変数名
は、render
関数での HTML 生成時に、コンテキストにおけるキーが '変数名'
の 値
に置き換えられることになります。例えばコンテキストの変数名がcontext
であれば、context['変数名']
で取得される値に置き換えられることになります。
前述の通り、コンテキストは辞書であり、キーには文字列を指定する必要がありますが、値には整数・文字列・クラスのインスタンス・リストなどの様々なオブジェクトを指定することが可能です。また、コンテキストには複数の要素を持たせても問題ありません。
ただし、テンプレートファイルから変数を参照する場合、その変数の参照先となるデータがコンテキストに存在する必要があります。したがって、その参照される変数の '変数名'
をキーとする要素を全て用意しておく必要があります。
コンテキストの重要性
テンプレート で、ウェブアプリのページは共通部分と動的に変化させる部分の2つから構成されると説明しましたが、コンテキストは、この動的に変化させることを実現するために必要なデータとなります。
テンプレートファイルから変数を参照するようにしておけば、コンテキストの要素における 値
に応じて生成される HTML が変化することになります。この 値
をリクエストに応じた値に設定するようにすれば、テンプレートファイルの変数参照部分がリクエストに応じた値に動的に変化し、リクエストに応じた HTML を生成することができるようになります。
例えば、前述の下記のような辞書データを context
引数に指定した場合、render
関数実行時にテンプレートファイルにおける {{ name }}
部分が YamadaHanako
に変化することになります。
context = {
'name' : 'YamadaHanako',
}
それに対し、下記のような辞書データを context
引数に指定した場合、render
関数実行時にテンプレートファイルにおける {{ name }}
部分が TanakaJiro
に変化することになります。
context = {
'name' : 'TanakaJiro',
}
このように、テンプレートファイルで変数を参照するようにしておけば、コンテキストに応じた HTML を生成することができます。さらに、コンテキストの要素をリクエストに応じて設定するようにすれば、1つのテンプレートファイルからリクエストに応じた無数の HTML を生成することが可能となります。
ここまで解説してきたように、テンプレートはリクエストに応じたページを表示するための仕組みであり、その役割はテンプレートファイルをビューに提供することになります。
それに対し、コンテキストを用意するのはビューの役割となります。ユーザーからのリクエストに応じられるよう、リクエストに応じたコンテキストを用意することが重要となります。
テンプレートファイル
続いて、テンプレートファイルの詳細について説明を行なっていきます。
スポンサーリンク
HTML の基となるファイル
前述の通り、テンプレートファイルはページの雛形であり、HTML の基となるファイルです。拡張子には HTML 同様に .html
が利用されます。
このテンプレートファイルからは HTML を生成することが可能で、前述で解説した通り、テンプレートファイルから HTML を生成する際には render
関数が利用されます。この render
関数を実行することで、テンプレートファイルの記述やコンテキストに従った HTML の生成が行われます。
テンプレートファイルの構成
このテンプレートファイルは、基本的には『HTML』と『Django テンプレート言語』と呼ばれる Django 特有の構文から構成されるファイルとなります。
render
関数で HTML が生成される際には、『Django テンプレート言語』部分のみが動的に変化することになります。逆に、『Django テンプレート言語』以外の部分はそのまま出力されることになります。つまり、テンプレートファイルにおける『HTML』部分は render
関数を実行しても変化しません。
したがって、ページの雛形部分、つまり共通部分は HTML で記述を行い、動的に変化させたい部分はDjango テンプレート言語で記述することになります。
Django テンプレート言語
この Django テンプレート言語は {
〜 }
で囲んだ形式で記述します。
つまり、雛形を構成する HTML の中に {
〜 }
を記述しておけば、その部分のみが render
関数実行時に動的に変化することなります。
この Django テンプレート言語には大きく分けて4種類のものが存在します。
- 変数
- タグ
- フィルター
- コメント
ここでは簡単に、各種 Django テンプレート言語について説明します。
変数
『変数』は {{ 変数名 }}
の形式で記述を行います。{{ 変数名 }}
は参照先の変数の値に置き換えを行うための記述となります。ここまでも何回か紹介してきましたね!
前述の コンテキスト で解説したように、テンプレートファイルからは変数を参照することができます。その変数の参照先はコンテキストとなります。{{ 変数名 }}
をテンプレートファイルに記述している場合、この部分が render
関数実行時に、コンテキストにおけるキーが '変数名'
の要素の値に置き換えられることになります。
例えば、{{ name }}
を記述したテンプレートファイルと、下記のコンテキストを render
関数の引数に指定した場合、render
関数実行時に {{ name }}
の部分が name
キーの値である YamadaHanako
に置き換えられた HTML が生成されることになります。
context = {
'name' : 'YamadaHanako',
}
また、テンプレートファイルでは {{ user.name }}
のようにインスタンスのデータ属性を参照するようなことも可能です。この場合、コンテキストの 'user'
キーの値としてはデータ属性 name
を持つオブジェクトを指定する必要があります。
特に多いのが、モデルのインスタンスをコンテキストの値に設定する例となります。この実例はモデルの解説ページで紹介します。
タグ
2つ目が『タグ』で、これは {% タグ名 %}
の形式で記述します。このタグは『テンプレートタグ』とも呼ばれます。
タグの用途は様々で一言で説明するのは困難ですが、簡単に言えば何かしらの処理や制御を行うための記述であると考えると良いと思います。テンプレートファイルに {% タグ名 %}
の記述があった場合、render
関数内で タグ名
に応じた処理が行われ、その結果が {% タグ名 %}
部分に埋め込まれることになります。
また、タグ名
によっては、{%
〜 %}
の中に単にタグ名を記述するだけでなく、引数の指定が必要なものもありますし、処理の終端(例えばループ処理の終端)を示すための {%
〜 %}
を別途記述する必要のあるものもあります。
また、引数には変数を指定することが可能なものもあります。この場合は、テンプレートファイルから変数が参照されることになりますので、その参照先としてコンテキストに変数に応じた要素を用意しておく必要があります。
例えば {% for user in users %}
は users
の各要素に対してループを行うための記述となります。この for
タグにおいては、処理をループさせる範囲を特定するために終端を表す {% endfor %}
の記述が必要になります。
例えば下図のような for
タグがテンプレートファイルに記述されている場合、{% for user in users %}
〜 {% endfor %}
の内側の処理が users
の要素数分繰り返し実行され、各要素の情報が出力されることになります。
また、この記述における users
はテンプレートファイルが参照する変数となりますので、コンテキストには 'users'
をキーとする要素を用意しておく必要があります。さらに、この場合は users
はイテラブルなオブジェクトとして扱われることになるため、'users'
の値はリストなどのイテラブルなオブジェクトである必要があります。for
タグから参照することの多いオブジェクトがクエリーセットになります。このクエリーセットに関してはモデルの解説の中で紹介します。
ここでは for
タグの紹介を行いましたが、他にも様々なテンプレートタグが存在します。各種テンプレートタグについては別途ページを作成して解説を行いたいと思います。
フィルター
フィルターは、参照する変数を加工する仕組みになります。
フィルターを利用すれば、変数 で説明した {{ 変数名 }}
を変数の値にそのまま置き換えるのではなく、変数を何らかの形に加工したものに置き換えることができます。また、テンプレートタグから参照する変数の値を加工することもできます。
フィルターは、変数名 | フィルター名
の形式で記述を行なって利用します。また、フィルターによっては引数を受け取るものもあり、その場合は 変数名 | フィルター名:引数
の形式で記述を行うことで引数を指定することになります。
例えば、フィルターの1つに length
が存在します。この length
は、変数を、その変数の要素数や長さに変換するフィルターとなります。例えば、コンテキストの 'users'
キーの値として要素数が 10
のリストが指定されている場合、テンプレートファイルに {{ users | length }}
が記述されていれば、この部分が HTML 生成時に 10
に置き換えられることになります。特にモデルを利用しだすとクエリーセットと呼ばれるデータを扱う機会が多くなり、クエリーセットの要素数を HTML に出力したい場合等に length
はよく利用されます。
また、フィルターには truncatechars
というものも存在し、これを利用することでページに表示される文字列を引数以下の文字数で自動的に切り詰めることができるようになります。例えば、コンテキストの 'text'
キーの値として 'abcdefghijk'
という文字列が指定されている場合、テンプレートファイルに {{ text | truncatechars:3 }}
と記述しておけば、HTML 生成時に下記の文字列に置き換えられることになります。
ab…
文字列が引数に指定した文字数以下に切り詰められるため、文字列が長すぎるとレイアウトが崩れてしまう様な場合に便利です。
また、前述の通り、テンプレートタグから参照する変数の加工を行うこともできます。例えば下記のように記述を行えば、users|length
は users
の要素数に変換されることになりますので、users
の要素数が 0
以外の場合のみ Hello World
が HTML に埋め込まれることになります。
{% if users|length != 0 %}
Hello World
{% endif %}
コメント
さらに、通常のプログラミング言語や HTML と同様に、Django テンプレート言語にもコメント機能が存在します。Django テンプレート言語でのコメントの書き方は2種類あります。
1つが下記の形式の書き方で、この場合は {#
〜 #}
の部分がコメントとして扱われることになります。特定の1行をコメントアウトしたり、行内の一部をコメントアウトするようなこともできますが、この書き方では複数行を一度にコメントアウトトするようなことはできません。
{# コメントととして扱われる #}
複数行を一度にコメントアウトしたい場合は、下記のようにテンプレートタグとしてコメント部分を指定する必要があります。
{% comment '不要になったためコメントアウト' %} コメント として 扱われる {% endcomment %}
スポンサーリンク
テンプレートファイルの置き場所
続いてテンプレートファイルの置き場所について説明していきます。
置き場所
テンプレートファイルの置き場所は下記となります。
プロジェクト名/アプリ名/templates/アプリ名/
テンプレートファイルの置き場所をフォルダ構成で図示すると下の図のようになります。
プロジェクト名
のフォルダは startproject
コマンド実行によって、プロジェクト名
フォルダの直下の アプリ名
のフォルダは startapp
コマンド実行によってそれぞれ自動的に作成されます。
ですが、その下にある templates
フォルダと アプリ名
フォルダは自動的には作成されませんので、手動でフォルダを作成しておく必要があります。
そして、上記のフォルダの中に .html
という拡張子のテンプレートファイルを、後述の 必要となるテンプレートファイル で解説しているように、ウェブアプリに必要な分だけ用意しておく必要があります。
テンプレートファイルのパス
また、上記のフォルダの中にテンプレートファイルを置いた場合、アプリ内のファイル、例えば views.py
や他のテンプレートファイルからは次のパスによりアクセスすることができるようになります。
アプリ名/ファイル名
例えば、アプリ名が app1
でテンプレートファイルのファイル名が index.html
である場合、views.py
から render
関数を実行する際には下記のように引数を指定することになります。
render(request, 'app1/index.html')
要は、templates
フォルダから見たテンプレートファイルの相対パスを指定すれば良いことになります。
必要となるテンプレートファイル
ここまで説明してきたように、テンプレートの仕組みを利用することで、1つのテンプレートファイルから無数の HTML を生成することができるようになります。
ただし、テンプレートファイルから生成可能な HTML は同じ雛形のものだけになります。要は同じような構成の HTML しか生成できません。そのため、構成が大きく異なるような HTML を生成するためには、別のテンプレートファイルを用意する必要があります。
そのため、ウェブアプリの開発時には基本的には複数のテンプレートファイルを用意しておくことになります。
基本的には、ウェブアプリで表示したいページの種類分のテンプレートファイルを作成することになると思います。例えば、ウェブアプリで『ログインページ』『マイページ』『登録ユーザーの一覧ページ』の3つの種類のページを表示できるようにしたいのであれば、3つのテンプレートファイルを作成する必要がある可能性が高いです。
ただし、ページの種類が異なってもページの雛形は同様である場合もあるので、その場合は1つのテンプレートファイルを複数のページで使い回すようなことも可能です。
例えば『マイページ』と『他のユーザーのページ』はページの種類は異なるものの、ページの雛形は同じである場合があります。この場合は同じテンプレートファイルを利用できることになります。
ただ、ウェブアプリによっては『マイページ』と『他のユーザーのページ』のページの構成を大きく異なるものにしたい場合もあるかもしれません。この場合はこれらのページ用のテンプレートファイルを個別に用意する必要があります。
ということで、どのようなテンプレートファイルをどれだけ用意するかはウェブアプリによって異なります。
重要なのは、自身が開発したいウェブアプリの構成を考え、その構成に応じて必要な分だけテンプレートファイルは用意することになります。
テンプレートの継承
複数のテンプレートファイルを作成するのにあたって覚えておきたいのが『テンプレートの継承』になります。
このテンプレートの継承について説明する前に、一点注意点について説明しておきます。このページのここまでの解説では、『共通』という言葉は「同じ種類のページに対し、リクエストの内容(例えばユーザーなど)に関らず同じ構成となる部分」に対して使ってきましたが、この節では『共通』という言葉を「種類の異なるページではあるものの同じ構成となる部分」に対して使うので、この違いに注意してください。
例えば、下図はマイページとユーザー一覧のページの例を示すもので、種類の異なるページではあるものの、ページのヘッダー部分とフッター部分(青色背景部分)は共通です。
こういった共通部分は、各種テンプレートファイル、この例で言えば、マイページ用のテンプレートファイルとユーザー一覧ページ用のテンプレートファイルそれぞれに記述するのではなく、親テンプレートファイルを用意し、それを各種ページ向けの子テンプレートから継承することで実現することができます。
テンプレートファイルの作成は当然ページの種類が多くなればなるほど作業が大変になります。ですが、このテンプレートの継承を利用することで、共通部分は1つの親テンプレートファイルの記述のみで済むようになるため、ある程度テンプレートファイルの作成を効率的に行うことができるようになります。
また、テンプレートファイルの修正も楽になり、さらに各種ページの見た目の統一化も図りやすくなります。メリットが多いので是非テンプレートの継承は覚えておきましょう!
テンプレートの継承方法
このテンプレートの継承は Django テンプレート言語 でも紹介したテンプレートタグを利用して実現します。後述でも解説しますが、具体的には extends
タグの利用により継承を実現することができます。
また、テンプレートの継承を行うためには、親テンプレートファイル(継承元となるテンプレートファイル)と親テンプレートファイルを継承する子テンプレートファイルを用意することになります。これらのファイルに関しても テンプレートファイルの置き場所 で説明した下記フォルダに設置します。
プロジェクト名/アプリ名/templates/アプリ名/
親テンプレートファイルの作成
テンプレートの継承を行うにあたり、まず親テンプレートファイルの作成を行います。この親テンプレートファイルでは、各種ページで共通となる部分をテンプレートファイルとして記述を行います。
また、親テンプレートファイルでは子テンプレートファイルごとに内容を変化させたい部分をブロックとして定義します。ブロックは block
タグにより定義することが可能で、例えば {% block ブロック名 %}{% endblock %}
と記述を行うことで、ブロック名
という名前のブロックを定義することができます。ブロックは1つのテンプレートファイルの中に複数個定義することも可能です。
子テンプレートファイルの作成
さらに、子テンプレートファイルでは、親テンプレートファイルを継承することを意味するテンプレートタグの記述と、親テンプレートファイルで用意されたブロックのコンテンツ(中身)の記述を行います。ブロックのコンテンツでは、他のテンプレートタグの記述や変数の参照を行うことも可能です。
まず、親テンプレートファイルの継承は、{% extends 親テンプレートファイルのパス %}
のテンプレートタグにより実現することができます。
また、ブロックのコンテンツの記述は親テンプレートファイルで定義されるブロックの種類ごとに行う必要があります。子テンプレートファイルの中に {% block ブロック名 %}
〜 {% endblock %}
を記述しておけば、その内側に記述した内容が ブロック名
のブロックのコンテンツとして指定されることになります。
これで親テンプレートファイルと子テンプレートファイルが作成できたことになります。
また、render
関数の template_name
引数には子テンプレートファイルのパスを指定するようにします。
これにより、render
関数が実行された際に、extends
タグによって親テンプレートファイルが読み込まれ、さらに親テンプレートファイルに定義されたブロックに子テンプレートで記述されたブロックのコンテンツが埋め込まれることになります。具体的には、親テンプレートファイルにおける {% block ブロック名 %}{% endblock %}
の部分が、子テンプレートファイルにおける {% block ブロック名 %}
〜 {% endblock %}
の中に記述された内容に置き換えられます。
つまり、親テンプレートファイルさえ作成しておけば、子テンプレートファイルでは継承を行うための記述とブロックのコンテンツの記述さえ行えば良いようになるため、テンプレートファイルの作業効率が上がります。
もちろん、親テンプレートファイルも子テンプレートファイルもテンプレートファイルとなりますので、Django テンプレート言語を記述して変数の埋め込みやテンプレートタグによる制御を行うこともできます。
テンプレートの継承例
次はテンプレートの継承の具体例を見ていきましょう!
ここでは、アプリ名は app1
とし、親テンプレートファイルのファイル名は base.html
であることを前提に具体例を示していきます。
前述の通り、親テンプレートファイルには各種ページで共通となる部分の HTML の記述とブロックの定義を行います。簡単ですが、下記は親テンプレートファイルの具体的な例となります(a
タグに指定している URL はてきとうなものになっているので注意してください)。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<header>
<h1>マイアプリ</h1>
<nav class="navbar navbar-expand navbar-light bg-light">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="dummy1">トップページ</a>
</li>
<li class="nav-item">
<a class="nav-link" href="dummy2">マイページ</a>
</li>
<li class="nav-item">
<a class="nav-link" href="dummy3">ユーザー一覧</a>
</li>
</ul>
</nav>
</header>
<main class="container">
{% block main %}{% endblock %}
</main>
<footer>
<p>https://daeudaeu.com/</p>
</footer>
</body>
</html>
この親テンプレートファイルは下図のようなブロックを定義するファイルとなります。
要はページのタイトル部分と本文部分がブロックとなっており、その他の部分は各種ページで共通のものとなるように定義を行なったテンプレートファイルとなります。
ページのタイトル部分のブロックはブロック名が title
であり、本文部分のブロックはブロック名が main
となります。これらのブロックのコンテンツは子テンプレートファイル側に記述する必要があります。
したがって、子テンプレートファイルは下記のように作成を行う必要があります。下記では2つの子テンプレートファイルの例を示しています(mypage.html
と userlist.html
)。
{% extends "app1/base.html" %}
{% block title %}
マイページ
{% endblock %}
{% block main %}
<h2>マイページ</h2>
<p>ユーザー名 : 山田太郎</p>
<p>アカウント作成日 : 2023/2/27</p>
<p>メールアドレス : taro@yamada.jp</p>
{% endblock %}
{% extends "app1/base.html" %}
{% block title %}
ユーザー一覧
{% endblock %}
{% block main %}
<h2>ユーザー一覧</h2>
<table>
<thead>
<tr>
<th>ユーザー</th>
</tr>
</thead>
<tbody>
<tr><td>山田太郎</td></tr>
<tr><td>山田花子</td></tr>
<tr><td>田中二郎</td></tr>
<tr><td>佐藤三郎</td></tr>
</tbody>
</table>
{% endblock %}
上記の mypage.html
と userlist.html
は共通した記述になっており、まず1行目で親テンプレートファイルである app1/base.html
の継承を行なっています。テンプレートファイルの置き場所 で説明したように、アプリ内のファイルからはテンプレートファイルを アプリ名/テンプレートファイル名
によって参照可能です。
その後、mypage.html
と userlist.html
ではブロック title
のコンテンツの記述とブロック main
のコンテンツの記述をそれぞれを行なっています。これらは、各ファイルで同じブロックに対してコンテンツを記述していることになりますが、記述内容が異なるため、親テンプレートファイルのブロックに埋め込まれた際には異なる内容の表示が行われることになります。
実際に、render(request, 'app1/mypage.html')
を実行した際には、下図のようなページの HTML が生成されることになります。
また、render(request, 'app1/userlist.html')
を実行した際には下図のようなページの HTML が生成されることになります。
ブロック部分のみが使用する子テンプレートファイルによって異なっていることが確認できると思います。それ以外の部分は親テンプレートファイルのものがそのまま使用されています。
このように、親テンプレートファイルで各種ページの共通部分を用意し、その中に各種ページの固有部分をブロックとして埋め込む仕組みがテンプレートの継承となります。
上記の例では利用していませんが、各種テンプレートファイルからテンプレートタグや変数の参照等も利用可能です。
テンプレートの継承のメリット
前述でも少し触れましたが、テンプレートの継承にはたくさんのメリットがあります。
まず、テンプレートの継承の仕組みを利用することで、子テンプレートファイル側は extends
タグによる継承とブロックのコンテンツの記述さえ行えば良くなるため、テンプレートファイル作成の効率が上がります。
また、各種ページで共通となる部分は親テンプレートファイルのみに記述されるようになるため、共通部分の修正が必要になった際に修正が必要となるのは親テンプレートファイルのみとなり、修正の効率も上がります。逆に継承を利用していなかった場合、共通部分に修正が必要になった際には全てのテンプレートファイルの修正が必要となってしまいます…。また、この場合、修正漏れが発生する可能性もあります。
さらに、共通部分を1つのテンプレートファイルに記述するようになることで、自然とウェブアプリの各種ページの見た目に統一感が生まれることになります。
最初は面倒に感じるかもしれませんが、テンプレートの継承はメリットが多いため、是非積極的に利用するようにしてください!
スポンサーリンク
ビューとテンプレートの関係性
最後にテンプレートの利用例を示す前に、ここで今までのまとめとしてテンプレートとビューの関係性について解説しておきたいと思います。
テンプレートの役割
ここまでの説明の通り、テンプレートはテンプレートファイルを提供することが役割であり、具体的には、テンプレートの役割は下記を行なってテンプレートファイルを提供することになります。
- 『HTML』と『Django テンプレート言語』から構成されるテンプレートファイルを作成する
- テンプレートファイルはウェブアプリで表示するページに応じて必要な分だけ作成する
- テンプレートの継承を利用しても OK
- 作成したテンプレートファイルをテンプレートファイルの置き場所に置く
そして、このテンプレートファイルの提供先はビューとなります。あくまでもテンプレートの役割はテンプレートファイルの提供であり、テンプレートファイルを利用するのはビューとなります(もっと正確に言えば、利用するのはビューから実行される render
関数となります)。
ビューの役割
また、ビューにとって重要なのは、リクエストに応じたレスポンスを返却することになります。そして、レスポンスには HTML が含まれるため、リクエストに応じた HTML を生成する必要もあります。
そのため、複数のテンプレートファイルが存在する場合、リクエストに応じた HTML を生成するために、適切にテンプレートファイルを選択し、そのファイルのパスを render
関数の引数に指定する必要があります。
また、テンプレートファイルから変数が参照される場合、リクエストに応じた HTML を生成するために、適切にコンテキストを作成して、そのコンテキストを render
関数の引数に指定する必要もあります。
要は、テンプレートはテンプレートファイルを提供することが役割であり、そのテンプレートファイルを適切に利用して HTML を生成するのはビューの役割となります。
また、ウェブアプリが受け付けるリクエスト先の URL に関しては urls.py
の URL のマッピングによって決まります。ウェブアプリでリクエスト先の URL に応じた処理が実行できるよう、適切に urls.py
で URL のマッピングも行なっておく必要があります。
結局、重要なのはウェブアプリがユーザーのリクエストに応じた処理の実行・レスポンスの返却を行えるようにすることなので、開発者目線で考えれば、それを実現するために urls.py
やビュー、さらには今回紹介したテンプレートファイルを作成・用意しておくことが重要となります。
特にテンプレートファイルの作りによって、ビューの作成するコンテキストに必要なキー等が決まることになりますので、テンプレートの参照する変数とビューの作成するコンテキストとで話が合うように開発を行うことも重要となります。
スポンサーリンク
掲示板アプリでテンプレートを利用してみる
では、ここまで説明してきた内容を踏まえて、実際にテンプレートの利用例を示していきたいと思います。
この Django 入門に関しては連載形式となっており、ここでは前回下記ページの 掲示板アプリでビューを利用してみる で作成したウェブアプリに対してテンプレートの仕組みを導入する形で、テンプレートの利用例を示していきたいと思います。

テンプレートフォルダの作成
では、前述の通り、掲示板アプリでビューを利用してみる で示したウェブアプリを変更してテンプレートを導入していきたいと思います。
まず、テンプレートファイルの置き場所となるフォルダを作成します。テンプレートファイルの置き場所 で解説したように、テンプレートファイルの置き場所は下記のパスとなります。
プロジェクト名/アプリ名/templates/アプリ名/
今回作成しているウェブアプリにおいて、プロジェクト名は testproject
、アプリ名は forum
となります。
現状では、templates
フォルダ以下が未作成の状態となっていますので、forum
フォルダの下に templates
フォルダを、さらにその templates
フォルダの下に forum
フォルダを新規作成してください。
例えば、ターミナル等を利用しているのであれば、プロジェクトフォルダ testproject
の中(manage.py
が存在するフォルダ)で下記のコマンドを実行することで、これらのフォルダを作成することができます。
% mkdir forum/templates
% mkdir forum/templates/forum
テンプレートファイルの作成
フォルダが作成できれば、次はいよいよテンプレートファイルを作成していきます。
現状の forum
の views.py
では下記の5つの関数を用意しています。
index_view
:トップページを表示する(リダイレクトするだけ)users_view
:ユーザー一覧ページを表示するuser_view
:特定のユーザーの詳細情報ページを表示するcomments_view
:投稿済みコメント一覧ページを表示するcomment_view
:特定のコメントの詳細情報ページを表示する
これらのビューの関数では、自身の関数の中で HTML を生成し、それをボディとする HttpResponse
のインスタンスを返却するようになっています。
これらの関数の対し、下記の4つのテンプレートファイルを導入していきます。
users.html
:ユーザー一覧ページのテンプレートuser.html
:特定のユーザーの詳細情報ページのテンプレートcomments.html
:投稿済みコメント一覧ページのテンプレートcomment.html
:特定のコメントの詳細情報ページのテンプレート
つまり、これらのテンプレートファイルを導入することで、各種ビューの関数が表示したいページのテンプレートが上記のテンプレートファイルから提供されるようになります。
ビューの関数が5つであるのに対し、導入するテンプレートファイルが4つなのは、index_view
が単純に他のページへリダイレクトを行うだけで、HTML の生成が不要だからです
したがって、各種ビューの関数はテンプレートファイルから参照される変数を提供するためのコンテキストの作成と、render
関数による HTML の生成および render
関数の返却値の返却を行えば良いだけになります(render
関数の引数として、使用するテンプレートファイルの指定を行う必要もあります)。
つまり、テンプレートがページの雛形を提供する役割を果たすため、ビューはページの雛形に関しては考える必要がなく、雛形に対して埋め込みたいデータの準備、および、表示したいページに合わせた雛形の選択を行えば良いだけになります。その分ビューの関数の実装はシンプルになります。
また、テンプレートの継承 で説明したように、テンプレートファイルは親テンプレートファイルを継承することが可能です。今回は、親テンプレートファイルとして base.html
を作成し、この base.html
を継承する形で上記の4つのテンプレートファイルを作成していきたいと思います。
ということで、ここからは base.html
+上記の4つのテンプレートファイルの作成を行なっていきたいと思います。前述の通り、これらのテンプレートファイルは下記フォルダの中に作成していくことになります。
testproject/forum/templates/forum/
base.html
では、まずは親テンプレートファイルとなる base.html
を作成していきます。
今回は、base.html
を下記のように作成したいと思います。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<header>
<nav class="navbar navbar-expand navbar-dark bg-primary">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link navbar-brand" href="{% url 'index' %}">掲示板</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'users' %}">ユーザー一覧</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'comments' %}">コメント一覧</a>
</li>
{% comment 'フォーム説明後に追加' %}
<li class="nav-item">
<a class="nav-link" href="{% url 'post' %}">コメント投稿</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'register' %}">ユーザー登録</a>
</li>
{% endcomment %}
</ul>
</nav>
</header>
<main class="container my-5 bg-light">
{% block main %}{% endblock %}
</main>
</body>
</html>
少し複雑なテンプレートファイルになっていますが、この base.html
は下図のような雛形を提供するテンプレートファイルとなっています。
要は、ナビゲーションバーと title
ブロックと main
ブロックを提供する親テンプレートファイルです。この base.html
を継承した子テンプレートファイルには、ナビゲーションバーが引き継がれることになります。また、base.html
で読み込んでいる CSS 等も引き継がれることになります。
また、base.html
では title
ブロックと main
ブロックの2つを定義しているため、子テンプレートファイル側で、各テンプレートで実現したい雛形となるように各ブロックのコンテンツを記述してやれば、それらのコンテンツが base.html
に埋め込まれることになります。
他のポイントについても説明しておくと、まず、この base.html
では Bootstrap の読み込みを行うようにしています。
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
この Bootstrap が読み込まれることで、Bootstrap で定義されているスタイルを各種テンプレートファイルから利用できるようになります。そして、テンプレートファイルの各タグで利用したいスタイルを class
に指定することで、見た目の綺麗なウェブアプリを簡単に実現することができます。
もちろん Django においても自身で CSS ファイルを作成し、自身で定義したスタイルを利用することも可能です。ただし、その場合はウェブアプリが動作するサーバーから CSS ファイルを提供できるようにする必要があり、そのための手順が若干面倒です。
そのため、今回は外部サイトから Bootstrap を取得し、Bootstrap で定義されるスタイルを利用するようにしています。もし、自身で作成した CSS ファイルを利用したい場合は、下記ページで手順を示していますので、詳しくは下記ページを参考にしていただければと思います。

また、base.html
では下記の部分を Django テンプレート言語 で説明したコメントを利用してコメントアウトをしています。
{% comment 'フォーム説明後に追加' %}
<li class="nav-item">
<a class="nav-link" href="{% url 'post' %}">コメント投稿</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'register' %}">ユーザー登録</a>
</li>
{% endcomment %}
上記に関しては、次の連載で説明する『フォーム』に関しての説明を終えた後に有効化を行います。
掲示板への投稿を Comment
クラスで扱っているため、コメントアウトの comment
と混在しやすいので注意してください
正直、後から考えて、このクラスの名前の付け方に失敗したなぁと思っています…
また、コメント以外にも、base.html
では Django テンプレート言語 で紹介したテンプレートタグの利用を行なっています。それが、下記の url
テンプレートタグになります。base.html
を確認すれば、いくつかの箇所でこのテンプレートタグを利用していることが確認できると思います。
<a class="nav-link" href="{% url 'users' %}">ユーザー一覧</a>
この url
テンプレートタグは、引数で与えられた URL 名から URL そのものに変換を行い、その変換結果を HTML に埋め込むタグとなります。
上記の場合は、'users'
が引数で与えられる URL 名となります。さらに、/forum/
から始まる URL に関しては forum
フォルダの urls.py
が参照されるようになっており、この urls.py
で下記のように URL に 'users'
という名前を付けるように設定しています。
path('users/', views.users_view, name='users'),
したがって、上記の url
テンプレートタグ部分は /forum/users/
に置き換えられ、さらに a
タグによって ユーザー一覧
という文字列に対してこの URL へのリンクが貼られることになります。
このように、url
タグは URL の名前から URL への置き換えを実現する重要なテンプレートタグであり、利用する機会も多いと思いますので是非覚えておいてください。
users.html
続いて、子テンプレートファイル側の作成を行なっていきます。
まずは users.html
を作成していきます。このテンプレートファイルはユーザー一覧を表示するための雛形となります。
今回は、下記のように users.html
を作成したいと思います。この users.html
は、変数 users
を参照しています。そのため、ビューの関数では 'users'
キーを持つコンテキストを用意してやる必要があります。後述の ビューの変更 で具体例を示しますが、今回は 'users'
キーの値として User
クラスのインスタンスのリストを指定したコンテキストを用意します。
{% extends "forum/base.html" %}
{% block title %}
ユーザー一覧
{% endblock %}
{% block main %}
<h1>ユーザー一覧(全{{ users|length }}人)</h1>
<table class="table table-hover">
<thead>
<tr>
<th>ユーザー</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td><a href="{% url 'user' user.id %}">{{ user.username }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
ポイントは、親テンプレートファイルである base.html
を継承しているところと、base.html
に用意されている title
ブロックと main
ブロックのコンテンツの記述を行なっている点になります。
また、このテンプレートファイルでは Django テンプレート言語 で紹介した length
フィルターと truncatechars
フィルターを利用しています。例えば、{{ users|length }}
部分はコンテキストで与えられる users
の要素数に加工されて HTML に埋め込まれることになります。
さらに、下記部分では for
タグを利用しており、これにより下記の 〜ループ処理〜
の部分が users
の各要素 user
に対して繰り返し実行されることになります。
{% for user in users %}
〜ループ処理〜
{% endfor %}
さらに、この繰り返しの中で users
の各要素 user
のデータ属性を参照してリンクの設定や名前の HTML への埋め込みなどを行うようにしています。
今回の例では単なるクラスである User
のインスタンスのリストをテンプレートファイルから参照することを想定していますが、実際に Django でウェブアプリを開発する際には、クエリーセットというモデルのインスタンスの集合を参照する機会が非常に多いです。まだモデルについての説明を行なっていないため、現状単なるクラスを利用しているだけです。
ですが、クエリーセットを参照するようになったとしても、上記のような for
タグで各インスタンスに対して処理を行う部分はそのまま利用できますし、この for
タグも利用する機会が多いので是非覚えておいてください。
user.html
続いて user.html
を作成していきます。このテンプレートファイルは特定のユーザーの詳細情報を表示するための雛形となります。
今回は、下記のように user.html
を作成したいと思います。この user.html
は、変数 user
を参照しています。そのため、ビューの関数では 'user'
キーを持つコンテキストを用意してやる必要があります。後述の ビューの変更 で具体例を示しますが、今回は 'user'
キーの値として User
クラスのインスタンスを指定したコンテキストを用意します。
{% extends "forum/base.html" %}
{% block title %}
{{ user.username }}
{% endblock %}
{% block main %}
<h1>ユーザー({{ user.id }})</h1>
<h2>{{ user.username }}の情報</h2>
<table class="table table-hover">
<tbody>
<tr><th>名前</th><td>{{ user.username }}</td></tr>
<tr><th>連絡先</th><td>{{ user.email|urlize }}</td></tr>
<tr><th>年齢</th><td>{{ user.age }}</td></tr>
</tbody>
</table>
{% endblock %}
継承を行なっている点は users.html
と同じです。
ポイントを挙げるとすれば、{{ user.email|urlize }}
の部分で、この部分では urlize
フィルターを利用しています。これにより、|
の前側の部分の URL やメールアドレスのテキストが、リンクを設定された状態のものに置き換えられることになります。
comments.html
次は comments.html
を作成します。このテンプレートファイルはコメント一覧を表示するための雛形となります。
今回は、下記のように comments.html
を作成したいと思います。この comments.html
は、変数 comments
を参照しています。そのため、ビューの関数では 'comments'
キーを持つコンテキストを用意してやる必要があります。後述の ビューの変更 で具体例を示しますが、今回は 'comments'
キーの値として Comment
クラスのインスタンスのリストを指定したコンテキストを用意します。
{% extends "forum/base.html" %}
{% block title %}
コメント一覧
{% endblock %}
{% block main %}
<h1>コメント一覧(全{{ comments|length }}件)</h1>
<table class="table table-hover">
<thead>
<tr>
<th>本文</th>
</tr>
</thead>
<tbody>
{% for comment in comments %}
<tr>
<td><a href="{% url 'comment' comment.id %}">{{ comment.text|truncatechars:20 }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
users.html
とは一覧として表示する対象が異なるものの、テンプレートファイルとしては同様の作りとなります。ということで、ポイントの説明は省略させていただきます。
comment.html
最後に用意するのは comment.html
になります。このテンプレートファイルは特定のコメントの詳細情報を表示するための雛形となります。
今回は、下記のように comment.html
を作成したいと思います。この comment.html
は、変数 comment
を参照しています。そのため、ビューの関数では 'comment'
キーを持つコンテキストを用意してやる必要があります。後述の ビューの変更 で具体例を示しますが、今回は 'comment'
キーの値として Comment
クラスのインスタンスを指定したコンテキストを用意します。
こちらも、特にコメントアウトしている部分以外は user.html
と同様の作りのため、ポイントの説明は省略します。
{% extends "forum/base.html" %}
{% block title %}
コメント
{% endblock %}
{% block main %}
<h1>コメント({{ comment.id }})</h1>
<table class="table table-hover">
<tr><td>本文</td><td>{{ comment.text }}</td></tr>
<tr><td>投稿日</td><td>{{ comment.date|date }}</td></tr>
</table>
{% endblock %}
スポンサーリンク
ビューの変更
テンプレートファイルが全て用意できましたので、次はビューの変更を行なっていきます。
各ビューの関数で行うことは、基本的にはコンテキストを用意し、さらに render
関数を実行することとのみとなります。ただし、render
関数の引数には使用するテンプレートファイルを指定する必要があり、各ビューの役割に応じて使用するテンプレートファイルを適切に選択して指定する必要があります。
具体的には、現状のビューには下記の関数を用意しており(index_view
はリダイレクトするだけなので省略)、
users_view
:ユーザー一覧ページを表示するuser_view
:特定のユーザーの詳細情報ページを表示するcomments_view
:投稿済みコメント一覧ページを表示するcomment_view
:特定のコメントの詳細情報ページを表示する
テンプレートから提供されるテンプレートファイルは下記の4つとなっていますので、
users.html
:ユーザー一覧ページのテンプレートuser.html
:特定のユーザーの詳細情報ページのテンプレートcomments.html
:投稿済みコメント一覧ページのテンプレートcomment.html
:特定のコメントの詳細情報ページのテンプレート
各ビューで使用するテンプレートファイルは下記のようになります。
users_view
:users.html
user_view
:user.html
comments_view
:comments.html
comment_view
:comment.html
なので、各種ビューの関数は、上記の使用するテンプレートファイルから参照される変数に合わせたコンテキストを作成し、上記のテンプレートファイルのパスとコンテキストを引数に指定して render
関数を実行することになります。テンプレートファイルのパスは templates
フォルダからの相対パスで記述する必要がある点に注意してください。
ということで、ここまで説明してきた内容を考慮すれば、views.py
は下記のように変更してやれば良いことになります。render
関数を利用するため、render
関数の import
が必要な点に注意してください。
from django.http import Http404
from django.shortcuts import redirect, render
class User:
def __init__(self, id, username, email, age):
self.id = id
self.username = username
self.email = email
self.age = age
import datetime
class Comment:
def __init__(self, id, text, date):
self.id = id
self.text = text
self.date = date
users = [
User(1, 'Yamada Taro', 'taro@yamada.jp', 18),
User(2, 'Yamada Hanako', 'hanako@yamada.jp', 22),
User(3, 'Sato Saburo', 'saburo@sato.jp', 53),
User(4, 'Takahashi Shiro', 'shiro@takahashi.jp', 64)
]
comments = [
Comment(1, 'おはようございます', datetime.datetime(2023, 3, 4, 12, 4, 0)),
Comment(2, 'いい天気ですねー', datetime.datetime(2023, 4, 5, 16, 21, 0)),
Comment(3, '明日もよろしくお願いします', datetime.datetime(2000, 12, 25, 1, 55, 0)),
Comment(4, 'おやすみなさい', datetime.datetime(2024, 1, 1, 1, 37, 0)),
Comment(5, '山路を登りながら、こう考えた。智に働けば角が立つ。情に棹させば流される。意地を通とおせば窮屈だ。とかくに人の世は住みにくい。', datetime.datetime(2012, 10, 8, 3, 49, 0)),
]
def index_view(request):
return redirect(to='comments')
def users_view(request):
context = {
'users' : users
}
return render(request, 'forum/users.html', context)
def user_view(request, user_id):
if user_id > len(users) or user_id < 1:
raise Http404('Not found user')
user = users[user_id - 1]
context = {
'user' : user
}
return render(request, 'forum/user.html', context)
def comments_view(request):
context = {
'comments' : comments
}
return render(request, 'forum/comments.html', context)
def comment_view(request, comment_id):
if comment_id > len(comments) and comment_id < 1:
raise Http404('Not found comment')
comment = comments[comment_id - 1]
context = {
'comment' : comment
}
return render(request, 'forum/comment.html', context)
下記ページの 掲示板アプリでビューを利用してみる で作成した views.py
では、views.py
の各関数の中で HTML の構成を自分で定義するようにしていました。

なので、関数の中身が若干複雑になっていましたが、上記の views.py
では HTML の構成は全てテンプレート側で定義するようになっているため、ほぼ、コンテキストの用意と render
関数の実行のみで処理が完結するようになっています。そして、これによって関数の中身がスッキリしていることを確認できると思います。
また、各関数ではテンプレートファイルが参照する変数に合わせてコンテキストを用意するようにしています。特に user_view
と comment_view
では引数で ID が指定されるようになっており、その ID に応じたインスタンスをコンテキストにセットするようにしていますが、不正な ID が指定された場合は、今まで通り例外を発生させる必要があります。
動作確認
ソースコードの変更は以上になります。最後に動作確認を行なっておきましょう!
開発用ウェブサーバーの起動
まずは、ウェブアプリにアクセスできるよう、Django 開発用ウェブサーバーを起動してください。この開発用ウェブサーバーの起動は、manage.py
が存在するフォルダ(プロジェクトの testproject
フォルダの中)で下記コマンドを実行することで実現できます。
% python manage.py runserver
これにより、ウェブブラウザ等のクライアントからリクエストを受け取るウェブサーバーが起動することになります。
ページ表示の確認
ということで、次はウェブブラウザを開き、アドレスバーに下記 URL を指定します。
http://localhost:8000/forum/comments/
そうすると、下の図のようなページが表示されると思います。
上記 URL へのリクエストがあった際には comments_view
が実行されることになり、comments_view
でははテンプレートファイル comments.html
から HTML が生成されることになります。comments.html
からは base.html
が継承され、上の図のように base.html
で用意したナビゲーションバーが表示されるようになっています。
また、base.html
で用意した title
ブロック部分と main
ブロック部分に、comments.html
に記述した各ブロックのコンテンツが埋め込まれるようにもなっています。
さらに、comments.html
では comments
を参照しており、comments_view
からはコンテキストとして views.py
で定義している comments
のリストが渡されるため、for
タグの繰り返しによって views.py
で定義している comments
の各要素の情報が HTML に埋め込まれて表示されるようになっています。ページの表示結果から、views.py
のリスト comments
の要素数と同じだけの本文が表示されていることが確認できると思います。また、本文として表示される内容が、comments
の各要素のデータ属性 text
と同様になっている点も確認できると思います。
また、全5件の 5
に関しては comments
を length
フィルターで加工した結果であり、コメントの最後の1つに関しては本文が長いため、truncatechars
フィルターで加工されて途中で途切れていることも確認できると思います。
このように、上図のようなページの表示結果から、テンプレートの継承やテンプレートタグ・フィルターの効果等を確認できると思います。
さらに、ページに表示されているいずれかの本文をクリックすれば、その本文に対応するコメントの詳細情報のページに遷移します。
この場合は comment_view
が実行されることになります。そして、base.html
で用意された各ブロックに comment.html
に記述されたブロックのコンテンツが埋め込まれる形で HTML が生成され、それがページとして表示されることになります。
この場合も、全体的な見た目は先ほど表示したコメント一覧のページと同様になります。これは、全体的な見た目は base.html
で定義しており、各種テンプレートがこの親テンプレートファイルを継承するようになっているためです。このように、継承を利用することで、全体的な見た目をウェブアプリ内のページ間で統一しやすくなります。
さらに、ナビゲーションバーの ユーザー一覧
をクリックすれば、次はユーザーの一覧ページを表示することができます。
この場合は users_view
が実行され、views.py
に定義されている users
の各要素の情報が表示されることになります。また、コメント一覧ページの時同様に、ユーザー名をクリックすれば、そのユーザーのページが表示されることも確認できると思います。
下記ページの 掲示板アプリでビューを利用してみる で紹介したページの表示例に比べれば、かなり見た目としては綺麗になったのではないかと思います。

ただし、これは別にテンプレートを利用するようになったからではなく、テンプレートを利用しなくても、ビューに直接記述する HTML を変更してやれば同じような見た目のページを実現することは実は可能です。
ですが、ビューに直接 HTML を記述すると views.py
のコード量が多くなり、メンテナンス性が下がって変更しにくくなったりバグが発生しやすくなったりしてしまいます。それに対し、ビューとテンプレートとで役割を分割し、HTML の構成の定義を全てテンプレート側に行わせるようにすることで、各ファイルのコード量も減ってメンテナンス性が上がり、変更もしやすくなります。
さらに、継承を利用することで各テンプレートファイルのコード量も減りますし、それに加えてウェブアプリ内の各ページの見た目も統一しやすくなります。全体的な構造が親テンプレートファイルに集約されるので、変更・修正もしやすくなります。
このあたりの、テンプレートを利用することで得られるメリットを、今回紹介した例で実感していただければ幸いです。最初はテンプレートファイルを利用する必要があって面倒に感じるかもしれませんが、開発するウェブアプリの規模が大きくなると、テンプレートを利用するメリットがより発揮されるようになると思います。
まとめ
このページでは、Django におけるテンプレートについて解説しました!
テンプレートはビューに対して HTML の雛形を提供する役割を持ち、ビューから HTML の構造を定義する役割を分離することで、メンテナンス性の高いウェブアプリを実現することが可能となります。
また、テンプレートは単なる HTML だけでなく、Django テンプレート言語を利用して記述することになります。Django テンプレート言語を利用することで、テンプレートファイルから変数を参照したり、テンプレートタグを利用してちょっとした処理を実現することもできますし、フィルターを利用して変数を加工したりすることもできます。
さらに、テンプレートは継承機能を持っており、これを利用することでテンプレートファイルの開発効率が上がりますし、さらにウェブアプリ内のページ間の構造を統一することもしやすくなります。
今回は深く説明しませんでしたが、もちろん CSS を読み込んでスタイルを適用することも可能です。ウェブアプリの見た目に拘りたい方は、是非 CSS やスタイルについても学んでみると良いと思います。
今回紹介したテンプレートの導入により、ページの表示に関してはかなりまともなウェブアプリを実現することができるようになりました!次の下記ページの連載ではフォームの解説を行い、フォームを導入することで、ユーザーからデータを受け取ったり、ユーザーと対話可能なウェブアプリを実現していきたいと思います!
