引き続き、Djangoのチュートリアルを進めていく。
前回までの記事はこちら。
今回は質問詳細ページのビューとなるdetail.htmlに、投票をおこなうためのフォームを実装する手順をまとめていく。
Contents
テンプレートファイルの編集
まずはテンプレートファイル(templates/polls/detail.html)に以下のコードを書く。
<h1>{{ question.question_text }}</h1> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} <form action="{% url 'polls:vote' question.id %}" method="post"> {% csrf_token %} {% for choice in question.choice_set.all %} <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}"> <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br> {% endfor %} <input type="submit" value="Vote"> </form>
途中で出てくるcsrf_tokenタグは、クロスサイトリクエストフォージェリ対策のもので、POST送信するフォームを作るときは必ず書くようにしておく。
フォームのactionには、投票ビューのURLを指定し、パラメータとして質問IDを渡すようにしている。
また補足として、forloop.counterはDjangoテンプレートのfor文で使用できるプロパティで、ループカウンターを取得することができる。
今回はこのカウンターを利用してフォームパーツ要素のIDとして設定した。
パラメータを受け取る投票ビューの構築
次に投票ビューの構築を進めていく。
polls/views.pyのvoteクラスを以下のとおり編集する。
from django.shortcuts import get_object_or_404, render from django.http import HttpResponse, HttpResponseRedirect from django.urls import reverse from .models import Choice, Question def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST['choice']) except(KeyError, Choice.DoesNotExist): return render(request, 'polls/detail.html', { 'question': question, 'error_message': "You didn't select a choice.", }) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
try文でPOST値を元に選択肢を取得しているが、この時もしPOST値としてchoiceを取得できなければKeyError例外へと処理が移り、error_messageを持たせて質問詳細ページへと画面を遷移させる。
try文が正常終了した場合はelse文へと処理が移り、選択肢の投票カウンターをインクリメントさせ、HttpResponseRedirectを返す。
投票後の結果ページのビューを作る
最後に投票が正常終了した時に遷移する、結果ページのビューを作る。
まずはpolls/views.pyのresultsクラスに以下のコードを書く。
def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question})
最後にテンプレートとなるtemplates/polls/results.htmlに以下のコードを書く。
<h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {% endfor %} </ul> <a href="{% url 'polls:detail' question.id %}">Vote again?</a>
開発サーバーで動作確認
ここまで出来たら、python manage.py runserverコマンドで開発サーバーを起動し、動作確認をおこなってみよう。
以下の質問詳細ページへアクセスする。
http://127.0.0.1:8000/polls/1/

選択肢チェックボックスのいずれかにチェックを入れ、Voteボタンを押すと以下の結果ビューへと画面が遷移され、現在の投票結果が表示される。

なお、選択肢にチェックを入れずにVoteボタンを押すと例外が走り、以下のエラーメッセージが表示される。

これで投票に関する簡単なビューを構築することができた。