目次
Django 最初のアプリケーション 3 (Viewの作成)
Pythonの概要も分かり易い.
を参考にサンプルアプリケーションを作成してみる
方針
Djangoアプリケーションにて、ビューは、Webページの『型』であり、特定の機能や、テンプレートを提供する。
- たとえば、ブログアプリケーションでは以下のようなビュー。
- ホームページ - 最新の2、3のエントリを表示
- エントリの詳細ページ - あるエントリへのパーマリンク
- 年別アーカイブページ - ある年のエントリを月別表示
- 月別アーカイブページ - ある月のエントリを日別表示
- 日別アーカイブページ - ある日のエントリを表示
- コメントページ - エントリへのコメント
- サンプルとして作成している Poll アプリケーションでは、以下の4つのビューを持たせる
- アーカイブページ - 最新の2、3の調査を表示
- 詳細ページ - 調査の質問を表示。結果は表示せず、投票フォームを表示
- 結果ページ - 調査結果のページ特定の調査についての結果
- 投票ページ - 特定の調査に対する投票を選択する
URLの設計
URLの構造を設計
- Djangoで作成されたページにアクセスすると、システムは ROOT_URLCONF設定を探す
- ROOT_URLCONFはPythonのドット区切り文法で記述された文字列
- Djangoはこのモジュールをロードし、呼び出されたURLパターンで、モジュールレベル変数を探す
- URLパターンは、以下の書式のタプル
(正規表現, Python コールバック関数 [, オプションのディクショナリ])
- Djangoは、最初に正規表現が一致するまでリストを下っていく
- 一致するものが見つかったら、Djangoは、HttpRequestオブジェクトを最初の引数として、キーワード引数として、正規表現から捕捉された値、オプションで任意のディクショナリ(タプルの3つ目の項目)を伴って、Pythonコールバック関数を呼び出す
オブジェクト詳細
urls.pyの編集
- 最初のアプリケーション 1で、django-admin.py startproject mysite を実行したとき、mysite/urls.py にデフォルトの URLconfを作成している。
- 自動的に、settings.pyファイルのROOT_URLCONF 設定 にて、そのファイルを指定している
ROOT_URLCONF = 'mysite.urls'
- mysite/urls.pyを以下のように編集
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Example:
# (r'^mysite/', include('mysite.foo.urls')),
(r'^polls/$', 'mysite.polls.views.index'),
(r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'),
(r'^polls/(?P<poll_id>\d+)/results/$', 'mysite.polls.views.results'),
(r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('dhttp://typea.info/tips/wiki.cgi?action=EDIT&page=Django+%BA%C7%BD%E9%A4%CE%A5%A2%A5%D7%A5%EA%A5%B1%A1%BC%A5%B7%A5%E7%A5%F3+3&artno=2jango.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
(r'^admin/(.*)', admin.site.root),
)
リクエストパラメータの解析
上記の例では、"/polls/23/"というリクエストがあった場合、DjangoはPythonモジュールをロードする。これは、r'^polls/(?P<poll_id>\d+)/$' にマッチするためであり、 mysite/polls/views.py.からdetail()関数が以下のように呼び出される。
detail(request=<HttpRequest object>, poll_id='23')
- poll_id='23' の部分は、(?P<poll_id>\d+)から来ている
- 丸括弧でパターンをを囲うことにより、テキストの一致を『捕捉』しビュー関数に引数として送信する。
- ?P<poll_id> がパターンにマッチした場合の名称を定義している。
- \d+ は正規表現で数字の連続
最初のビュー
ViewDoesNotExistエラー
- まだ、ビューを作成していないので、http://192.168.24.14:8080/polls/ にアクセスしても、以下のようにViewDoesNotExistエラーが表示される
- これは、index() 関数を mysite/polls/views.py. に実装していないため。
シンプルビューの実装
- mysite/polls/views.py に以下を記述してみる
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the poll index.")
テキストを出力するシンプルなビューが作成された
引数を取るビューの実装
- 引数をとる以下の関数を追加し、http://192.168.24.14:8080/polls/34/ にアクセス
def detail(request, poll_id):
return HttpResponse("You're looking at poll %s." % poll_id)
URLに入力したパラメータを取得できている
実際になにかするビュー
簡単なビューの作成
- ビューは次の2つのうちどちらかを行う責任がある。
- リクエストされたページのコンテンツを含んだHttpResponseオブジェクトを返す
- Http404のようなエラーを返す
- 先ほどの例で、HttpResponseにメッセージを直接与えたように、Pollの最新の5件を出力するようにハードコーディングしてしまうと、ページの見た目を変えるためにPythonのコードに手を加えなければいけなくなってしまう。Pythonからデザインを分離するために、テンプレートを使用する。
- 以下のコードはpolls/index.htmlテンプレートをロードし、Contextというテンプレート変数名とPythonオブジェクトのディクショナリを引き渡す
from django.template import Context, loader
from mysite.polls.models import Poll
from django.http import HttpResponse
def index(request):
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
t = loader.get_template('polls/index.html')
c = Context({
'latest_poll_list': latest_poll_list
})
return HttpResponse(t.render(c))
- ページをリロードするとテンプレートがまだないため、以下のようなエラーとなる
TemplateDoesNotExist at /polls/ polls/index.html
- 最初のアプリケーション 2でsetting.pyに指定したTEMPLATE_DIRS のディレクトリ以下に、pollsディレクトリを作成し、index.htmlファイルを作成する
- loader.get_template('polls/index.html') は、"[テンプレートディレクトリ]/polls/index.html"をファイルシステム上では指すようになる
index.html
{% if latest_poll_list %}
<ul>
{% for poll in latest_poll_list %}
<li>{{ poll.question }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
- ショートカット : render_to_response()
- テンプレートをロードするのによく使われる方法は、コンテキストとHttpResponseオブジェクトをテンプレートとともに詰めて返す。
書き直してみる
from django.shortcuts import render_to_response
from mysite.polls.models import Poll
def index(request):
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
return render_to_response('polls/index.html',{'latest_poll_list': latest_poll_list})
上と同じ結果が得られる
404エラー
Poll詳細ビューを作成してみる
from django.http import Http404from mysite.polls.models import Poll
:
def detail(request, poll_id):
try:
p = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
return render_to_response('polls/detail.html', { 'poll': p })
- Poll のIDが見つからない場合、HTTP 404エラーを返す
- detail.htmlにとりあえず、以下の内容を記述
{{ poll }}
- 存在するIDを指定
- 存在しないIDを指定
- ショートカット : get_object_or_404()
- Djangoはこのような場合にもショートカットを提供
from django.shortcuts import render_to_response, get_object_or_404
from mysite.polls.models import Poll
def detail(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
return render_to_response('polls/detail.html', { 'poll': p })
- get_list_or_404()関数も、同様に動作する。get()の代わりに、filter()を利用することを除いて。リストが空の場合、404エラーを返す。
テンプレートシステムを利用する
- detail()ビューは、次のような感じ
<h1>{{ poll.question }}</h1>
<ul>
{% for choice in poll.choice_set.all %}
<li>{{ choice.choice }}</li>
{% endfor %}
</ul>
URLconfs
簡単にする
- 各コールバック関数共通の、「mysite.polls.vews」をプレフィックスとして外だしできる
urlpatterns = patterns('mysite.polls.vews',
(r'^polls/$', 'index'),
(r'^polls/(?P<poll_id>\d+)/$', 'detail'),
(r'^polls/(?P<poll_id>\d+)/results/$', 'results'),
(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'),
)
分割する
- Pollアプリケーションの可搬性を高める
- 今までの、mysite/urls.py を mysite/polls/urls.py にコピー
- mysite/urls.py
- mysite/polls/urls.pyを取り込む
urlpatterns = patterns('',
(r'^polls/', include('mysite.polls.urls')),
)
- mysite/polls/urls.py
urlpatterns = patterns('mysite.polls.views',
(r'^$', 'index'),
(r'^(?P<poll_id>\d+)/$', 'detail'),
(r'^(?P<poll_id>\d+)/results/$', 'results'),
(r'^(?P<poll_id>\d+)/vote/$', 'vote'),
)

YAGI Hiroto (piroto@a-net.email.ne.jp)
twitter http://twitter.com/pppiroto
Copyright© 矢木 浩人 All Rights Reserved.