前回はこちら
この章でやること
- アプリのビューを追加
- 追加したビューのルーティング(URLconf)
名前空間の解決 - アプリ用 HTML 追加
- 404 エラーハンドリング
実行手順
- ビューの追加
polls/views.py
に関数どんどん追加するだけ。 - ルーティング
polls/urls.py
にパスを追加するだけ。
既にアプリ(polls)のルーティングはプロジェクト(mysite)にされている。
なので、polls/
以下の URL はプロジェクトに再度適応する必要はなく、アプリ内で自由に追加、削除ができる状態。 - html 追加
アプリ(polls)で使う HTML を追加する。
追加場所はmysite/polls/templates/polls
といった具合にネストさせる。テンプレートの名前空間
作ったテンプレートを (polls という別のサブディレクトリを作らずに) 直接 polls/templates の中に置いてもいいのではないか、と思うかもしれませんね。しかし、それは実際には悪い考えです。Django は、名前がマッチした最初のテンプレートを使用するので、もし 異なる アプリケーションの中に同じ名前のテンプレートがあった場合、Django はそれらを区別することができません。そのため、Django に正しいテンプレートを教えてあげる必要がありますが、一番簡単な方法は、それらに 名前空間を与える ことです。アプリケーションと同じ名前をつけた もう一つの ディレクトリの中にテンプレートを置いたのは、そういうわけなのです。なんか煩わしいなーと思ったけど、名前空間の解決のために行う模様。
プロジェクトの TEMPLATES には、Django がどのようにテンプレートをロードしレンダリングするかが書かれています。デフォルトの設定ファイルでは、 DjangoTemplates バックエンドが設定されており、その APP_DIRS のオプションが True になっています。規約により、 DjangoTemplates は INSTALLED_APPS のそれぞれの “templates” サブディレクトリを検索します。
ファイル名を
polls_index.html
とかにすれば別にサブディレクトリ使わなくても解決はできるけど、イケてないのは言うまでもない。
ただ、polls/view.py
には依然としてreturn render(request, "polls/index.html", context)
といった形で遷移先ハードコード は残る。 - ショートカット
ビュー関数を定義するとき、記述を省略できる。
本質的にやってることは変わらないので、import する対象がちょっと減るのがメリット。くらいな印象。
Beforefrom django.http import HttpResponse from django.template import loader from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] template = loader.get_template('polls/index.html') context = { 'latest_question_list': latest_question_list, } return HttpResponse(template.render(context, request))
After
from django.shortcuts import render from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] context = {'latest_question_list': latest_question_list} return render(request, 'polls/index.html', context)
- 404 エラー送出
django では雑に言うと Model が取得できない場合、DoesNotExist
例外がスローされます。
なので、オブジェクト取得時には以下を検討する必要があります。- try/except 構文を用いた例外ハンドリング
- 取得結果の判定
このへんの面倒さを一気にまとめたのが
django.shortcuts.get_object_or_404
で、オブジェクト取得できなかった場合は 404 レスポンスを返します。
HTTP じゃない場合とか、404 じゃなくてシステムエラーにしたいとか、要件によって使途は異なると思います。
本来存在すべきデータが存在しないのに 404 エラーを返すと、システムとしては異常な状態で稼働し続けている可能性があるのに、それを握りつぶす原因にもなります。 - テンプレート作成
- エンジン
先述の引用通り、テンプレートエンジンはDjangoTemplates
ですが、構文はJinja2
とかなり似ています。(マスタッシュ記法とか)
エンジンを変更する場合、settings.ps
のTEMPLATES
属性を変更すれば良いです。 - マスタッシュ記法とデリミタ
余談ですが、Vue.js などその他テンプレートエンジンとデリミタ({{ }}← これのこと)が競合する場合、デリミタを変更することでどちらかを選択することができます。 - 参照とループ、分岐
HTML 上でサーバサイドの返却値を参照したり、関数を使えたりするので便利ですが、保守性の面を考慮すると、分岐などはあまり書かない方が良いです。テーブルタグを用いて、要素を描画する際のループなどは積極的に使っていくのが良いと思います。 - HTML での URL 指定
href="/polls/{{ question.id }}/"
といったハードコードは極力避けましょう。HTML/urls.py/views.py と全てのコード上に URL に関する記述が存在し、変更・削除する際に面倒になります。
Django では名前空間を用いることで緩和できるので、積極的に代用していきます。
- エンジン
所感
思想的なことがドキュメントに丁寧に書いてあるのは非常に有益だと感じた。
このあたりがチーム全体でふわふわしてると、「俺はこう思う」のすり合わせが始まって、あまり有益ではないと感じる。
そういうのは業務中じゃなくて飲み会とかでやりたい。
規模感と設計粒度にもよるとは思うけど、Django 使うなら Django 思想に振り切ってしまった方が全体コストは安くなる実感もある。