djangoのチュートリアルをさくっとやってみた(フロントサイト構築)
前回の記事でdjangoチュートリアルの2までの内容(管理サイトの構築)まで行ったので、チュートリアルの3以降の内容(フロントサイトの構築)を行います。
3.2 フロントサイトの作成
投票一覧(index)・詳細(detail)・投票(vote)・投票結果(result)のページを作成します。
ルーティングの追加
各ページへのurlの設定を行います。
$ vi urls.py 6 urlpatterns = patterns('', 7 url(r'^polls/$', 'polls.views.index'), 8 url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'), 9 url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'), 10 url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), 11 url(r'^admin/', include(admin.site.urls)), 12 )
ビューの追加
一旦、各ページのダミーのビューを追加します。
これで「/polls」にアクセスすると表示はされるようになります。
vi polls/views.py 1 from django.http import HttpResponse 2 3 def index(request): 4 return HttpResponse("Hello, world. You're at the poll index.") 5 6 def detail(request, poll_id): 7 return HttpResponse("You're looking at poll %s." % poll_id) 8 9 def results(request, poll_id): 10 return HttpResponse("You're looking at the results of poll %s." % poll_id) 11 12 def vote(request, poll_id): 13 return HttpResponse("You're voting on poll %s." % poll_id)
投票一覧画面(index)の作成1
テンプレートを利用しない一覧の実装例
$ vi polls/views.py 1 from polls.models import Poll 2 from django.http import HttpResponse 3 4 def index(request): 5 latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] 6 output = ', '.join([p.question for p in latest_poll_list]) 7 return HttpResponse(output)
投票一覧画面(index)の作成2
テンプレートを利用した一覧の実装例
$ vi polls/views.py 1 from django.template import Context, loader 2 from polls.models import Poll 3 from django.http import HttpResponse 4 5 def index(request): 6 latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] 7 t = loader.get_template('polls/index.html') 8 c = Context({ 9 'latest_poll_list': latest_poll_list, 10 }) 11 return HttpResponse(t.render(c)) $ mkdir templates/polls $ vi templates/polls/index.html 1 {% if latest_poll_list %} 2 <ul> 3 {% for poll in latest_poll_list %} 4 <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li> 5 {% endfor %} 6 </ul> 7 {% else %} 8 <p>No polls are available.</p> 9 {% endif %}
投票一覧画面(index)の作成3
ショートカット(render_to_response)を利用した実装例
$ vi polls/views.py 1 from django.shortcuts import render_to_response 2 from polls.models import Poll 3 from django.http import HttpResponse 4 5 def index(request): 6 latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] 7 return render_to_response('polls/index.html', 8 {'latest_poll_list': latest_poll_list})
投票詳細画面(detail)の作成1
リクエストパラメータのpoll_idが存在しない番号の場合、HTTP STATUS 404を応答するように実装
$ vi polls/views.py 4 from django.http import Http404 ~(略)~ 10 def detail(request, poll_id): 11 try: 12 p = Poll.objects.get(pk=poll_id) 13 except Poll.DoesNotExist: 14 raise Http404 15 return render_to_response('polls/detail.html', {'poll': p}) $ vi templates/polls/detail.html 1 <h1>{{ poll.question }}</h1> 2 <ul> 3 {% for choice in poll.choice_set.all %} 4 <li>{{ choice.choice }}</li> 5 {% endfor %} 6 </ul>
投票詳細画面(detail)の作成2
HTTP STATUS 404の応答をショートカット(get_object_or_404)で実装
$ vi polls/views.py 1 from django.shortcuts import render_to_response, get_object_or_404 ~(略)~ 10 def detail(request, poll_id): 11 p = get_object_or_404(Poll, pk=poll_id) 12 return render_to_response('polls/detail.html', {'poll': p})
URLconfsの記述の簡略化と別ファイル化
urls.pyの記述をpolls/urls.pyに分離して記述も簡略化
(patternsの第一引数にパッケージ名を指定し簡略化)
// 「/polls」のルーティングは「polls/urls.py」に移動 $ vi urls.py 1 from django.conf.urls.defaults import patterns, include, url 2 3 from django.contrib import admin 4 admin.autodiscover() 5 6 urlpatterns = patterns('', 7 url(r'^polls/', include('polls.urls')), 8 url(r'^admin/', include(admin.site.urls)), 9 ) $ vi polls/urls.py 1 from django.conf.urls.defaults import patterns, include, url 2 3 urlpatterns = patterns('polls.views', 4 url(r'^$', 'index'), 5 url(r'^(?P<poll_id>\d+)/$', 'detail'), 6 url(r'^(?P<poll_id>\d+)/results/$', 'results'), 7 url(r'^(?P<poll_id>\d+)/vote/$', 'vote'), 8 )
投票フォーム(vote)と結果(result)の作成
一覧→投票→投票結果表示までの一連の流れを実装します。
// 投票詳細画面(detail)にフォームを組込 $ vi templates/polls/detail.html 1 <h1>{{ poll.question }}</h1> 2 3 {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} 4 5 <form action="/polls/{{ poll.id }}/vote/" method="post"> 6 {% csrf_token %} 7 {% for choice in poll.choice_set.all %} 8 <input type="radio" name="choice" id="choice{{ forloop.counter }}" 9 value="{{ choice.id }}" /> 10 <label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br /> 11 {% endfor %} 12 <input type="submit" value="投票する" /> 13 </form> // 結果画面(result)のテンプレートを作成 1 <h1>{{ poll.question }}</h1> 2 3 <ul> 4 {% for choice in poll.choice_set.all %} 5 <li>{{ choice.choice }} -- {{ choice.votes }} 票</li> 6 {% endfor %} 7 </ul> 8 9 <a href="/polls/{{ poll.id }}/">Vote again?</a> // 各ページのビューの実装 // detailのcontext_instanceはテンプレートの「csrf_token」のために必要 $ vi polls/views.py 1 from django.shortcuts import render_to_response, get_object_or_404 2 from django.template import RequestContext 3 from polls.models import Choice, Poll 4 from django.http import HttpResponseRedirect, HttpResponse 5 from django.core.urlresolvers import reverse 6 7 def index(request): 8 latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] 9 return render_to_response('polls/index.html', 10 {'latest_poll_list': latest_poll_list}) 11 def detail(request, poll_id): 12 p = get_object_or_404(Poll, pk=poll_id) 13 return render_to_response('polls/detail.html', {'poll': p}, 14 context_instance=RequestContext(request)) 15 16 def results(request, poll_id): 17 p = get_object_or_404(Poll, pk=poll_id) 18 return render_to_response('polls/results.html', {'poll': p}) 19 20 def vote(request, poll_id): 21 p = get_object_or_404(Poll, pk=poll_id) 22 try: 23 selected_choice = p.choice_set.get(pk=request.POST['choice']) 24 except (KeyError, Choice.DoesNotExist): 25 return render_to_response('polls/detail.html', { 26 'poll': p, 27 'error_message': "You didn't select a choice.", 28 }, context_instance=RequestContext(request)) 29 else: 30 selected_choice.votes += 1 31 selected_choice.save() 32 return HttpResponseRedirect(reverse('polls.views.results', args=(p.id,)))
汎用ビューの利用
$ vi polls/urls.py 1 from django.conf.urls.defaults import * 2 from django.views.generic import DetailView, ListView 3 from polls.models import Poll 4 5 urlpatterns = patterns('', 6 url(r'^$', 7 ListView.as_view( 8 queryset=Poll.objects.order_by('-pub_date')[:5], 9 context_object_name='latest_poll_list', 10 template_name='polls/index.html')), 11 url(r'^(?P<pk>\d+)/$', 12 DetailView.as_view( 13 model=Poll, 14 template_name='polls/detail.html')), 15 url(r'^(?P<pk>\d+)/results/$', 16 DetailView.as_view( 17 model=Poll, 18 template_name='polls/results.html'), 19 name='poll_results'), 20 url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'), 21 ) // 各ビュー(index,detail,result)の削除 $ vi polls/views.py 1 from django.shortcuts import get_object_or_404, render_to_response 2 from django.http import HttpResponseRedirect 3 from django.core.urlresolvers import reverse 4 from django.template import RequestContext 5 from polls.models import Choice, Poll 6 7 def vote(request, poll_id): 8 p = get_object_or_404(Poll, pk=poll_id) 9 try: 10 selected_choice = p.choice_set.get(pk=request.POST['choice']) 11 except (KeyError, Choice.DoesNotExist): 12 return render_to_response('polls/detail.html', { 13 'poll': p, 14 'error_message': "You didn't select a choice.", 15 }, context_instance=RequestContext(request)) 16 else: 17 selected_choice.votes += 1 18 selected_choice.save() 19 return HttpResponseRedirect(reverse('poll_results', args=(p.id,)))
これでチュートリアルは一通り完了です。少しdjangoを解った気分にはなれました。