Django – Tutorial – テンプレート

概要

DjangoドキュメントのチュートリアルPart3中”Write views that actually do something“の冒頭でビュー関数でのモデル操作を実装した後、テンプレートファイルを使った表示を実装している。

テンプレートの基礎についてはこちらを参照。

テンプレートディレクトリー/ファイルの作成

テンプレートファイルの内容

pollsディレクトリー下にtemplatesディレクトリーを、その下にpollsディレクトリーを作成する。そのディレクトリー下に以下の内容でindex.htmlファイルを作成する。

これから、polls/viewsモジュールからこのテンプレートを参照するよう編集していく。

パスの書き方の注意点

テンプレートファイルのアンカータグは以下のように書かれている。

当初/polls/{{ ... }}の部分の先頭の'/'を抜かして書いてしまって、polls/{{ ... }}としたところ、URLが以下のようになってしまった。

http://localhost:8000/polls/polls/2/

現在のアプリケーションからの相対パスになってしまったためで、

http://localhost:8000/polls/ + /polls/2/

と解釈されてしまう。先頭のスラッシュを入れるとホスト名をルートとするパスとなる。ただしこの記事の最後の方にあるDTLのurlタグを使うと、このような心配をしなくて済むようになる。

テンプレートの探索

ディレクトリー・ファイル構成は以下の通り。

config/settings.pyで、以下のように設定している。

  • INSTALLED_APPS'polls.apps.PollsConfig'を登録
    pollsが探索に含まれる
  • TEMPLATES'APP_DIRS'Trueに設定
    polls/templatesが探索に含まれる

ので、polls/templatesとそのサブディレクトリー下がテンプレートファイルの探索場所に含まれる。

ビューにおけるレンダリング

loaderによる標準形

ビューの編集

テンプレートファイルを導入した場合の標準形は以下の構成になる。

  • django.templateパッケージのloaderオブジェクトをインポート
  • loader.get_template('テンプレートへのパス')でテンプレートを読み込み
  • テンプレートのrenderメソッドでレンダリングした結果を、HttpResponseに渡す
    render(context, request)

動作確認

http://localhost:8000/pollsにアクセスすると、2つのリンクが表示される。

 

このHTMLのソースコードは以下のようになっている。

それぞれのリンクをクリックしたときの遷移先URLとブラウザー表示は以下の通り。

  • href="/polls/2/"
    • http://localhost:8000/polls/2/
    • You’re looking at question 2.
  • href="/polls/1/"
    • http://localhost:8000/polls/1/
    • You’re looking at question 1.

renderショートカット

loaderを用いた標準形では、

  1. テンプレートのローダーによってテンプレートファイルを読み込み、
  2. これをレンダリングした結果をHttpResponseに渡す、

という2段階の処理となっている。Djangoにはこれを1行で済ませるrenderショートカットが準備されている。renderショートカットを使って、indexビューをより簡潔にしてみる。

1行目のHttpResponseのインポートはまだ手を入れていない他のビュー関数のためで、renderによる処理には必要ない。loaderのインポートも不要で、必要なのは3行目のrenderのインポートのみ。

14行目がrenderショートカットを導入した効果で、この1行でリクエスト、テンプレート、contextの指定を済ませてレスポンスを返している。

render(request, 'テンプレートパス', context)

404エラーの実装

存在しないidへの反応

indexテンプレートではQuestionの2つの要素が表示され、それぞれid=1, 2をリクエストパラメーターとして渡している(href="/polls/1/"など)。ところがQuestionに存在しないidを指定したURLでアクセスすると以下のようなエラーがブラウザーに表示される。

このエラーの代わりに、404エラーで反応させたい。

例外処理による標準形

ビューの編集

現在のdetailビューは以下のような内容。

存在しないインスタンスを指定すると例外が投げられるので、それをキャッチして404エラーをレイズするようにする。

テンプレートの準備

またrenderで指定しているdetailテンプレートを、polls/template/pollsディレクトリーに以下の内容で作成しておく。

実行結果の確認

これで存在しないidの値を指定したときのエラーは以下のように変化する。メッセージがHttp404クラスのコンストラクターに与えたテキストになっている。

get_object_or_404ショートカット

Djangoには、上のような複数行の例外処理を一行で書くget_object_or_404ショートカットが準備されている。

以下のようにget_object_or_404ショートカットをインポートすると、1行でQuestionデータを取得し、存在しなければ404エラーをレイズしてくれる。

存在しないidを指定したときのエラー表示は以下のようになる。エラーメッセージの内容は固定されていて変更できないようだ。

なおsettings.pyDEBUGFalseにすると、ブラウザー表示は以下の2行のより簡素な内容になる

テンプレートシステム

DTLによる記述

先ほどのindexテンプレートの内容は1行で変数を表示するだけの内容だったが、これをテンプレートらしくDTL~テンプレート言語を使って以下のように書き換える。

そうすると大きな見出しでQuestionデータのテキストが表示され、そのQuestionデータに関連付けられたChoiceデータのテキストが箇条書きで表示される。

 

今回のDTLでは、オブジェクトの属性を得るのにドット検索が行われている。通常のPythonの場合リストや辞書型のオブジェクトの要素は[]で参照されるが、DTLではこの記述方法が使えない。代わりにドットを使って以下の順序で探していく

  1. 辞書型のキー
  2. オブジェクトの属性
  3. リストのインデックス

今回の例では、辞書型のキーで取得できず、オブジェクトの属性として取得に成功する。

URLのハードコーディング回避

ハードコーディングの問題

現時点でindexテンプレートのアンカー要素のURLは"/polls/{{ question_id }}/"と書かれている。

 

この場合にリンクが張られるdetailのURLはurlsで定義されていて、たとえば以下の通り。

http://localhost/polls/1

ここでプロジェクト進行中に以下のように変更することとなったとする。

http://localhost/polls/specifics/1

この場合、indexテンプレートのアンカー要素の内容を全て以下のように変更する必要がある。

href="/polls/specifics/{{ question.id }}/"

さらにindexテンプレート以外でもこのルーティングを使っている場合、その分だけ変更が生じてしまう。

ハードコーディングの回避

urls.pyの確認

まずpolls/urls.pydetailビューへのルーティングにname='detail'で名前が付けられていることに留意。

ビューの変更

index/view.py中、アンカー要素のURL部分を以下のように変更する。

  • href="..."のURL部分を{% url %}に入れ替え
  • このタグの引数に、urlsnameで指定した名前とパラメーターを書く

一般化した書き方は以下の通り。このとき、先頭や末尾の'/'は不要。

{% url 'urlsのnameで定義した名前' クエリーパラメーター %}

HTMLの確認

生成されるHTMLは以下の通り。

URLの変更

URLの変更が必要な場合、1箇所だけ、urlsの内容を変更すればよい。

以下のように生成されるHTMLもすべて変更される。

そして以下のようにアクセスできるようになる。

URLの名前空間管理

名前空間管理の必要性

DTLのurlタグで、ルーティングに付けた名前を使って抽象化することができた。ところが、先の例の場合pollsアプリケーションのdetailと同じ名前を他のアプリケーションでも使う場合、見分けがつかない。

そこで、ルート名がどのアプリケーションのものか分かるようにする必要がある。

urls.pyの編集

urls.pyに以下の1行を追加する。

indexテンプレートの編集

次にindexテンプレートの名前指定部分を、以下のように'アプリケーション名:ルート名'に変更。

この場合の実行結果は変わらないが、他のアプリケーションでもdetailという名前のルーティングがある場合でも、pollsアプリケーションの同名のdetailが識別される。

urlsapp_nameが定義されている状態でurlタグでpolls:を書かないと以下のエラーになる。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です