Djangoのチュートリアル 6 フォームを書く
今回は、Djangoで作ったページにフォームを追加していきます。前回までの記事はこちらです。
Djangoのチュートリアル 1 インストールから最初のビュー作成まで - pyhaya’s diary
Djangoのチュートリアル 2 モデルを作成する - pyhaya’s diary
Djangoのチュートリアル 3 ビューとモデルを組み合わせる - pyhaya’s diary
Djangoのチュートリアル 4 HTMLに慣れる - pyhaya’s diary
pyhaya.hatenablog.com
目次
フォームとは
Webページにおけるフォームというのは、Webページにおいてユーザーが入力を行う部分になります。通常はform
タグを使って、その中にinput
タグなどを使って入力部を作っていきます。例えばお問い合わせフォームなどがあります。詳しくは下のページを見てください。
html-coding.co.jp
フォームの例
フォームに慣れるためにいくつかフォームを作ってみます。html
タグなどは省略して、body
内のみを書いていきます。
<form method="POST" action=""> <p>名前<input type="text"></p> <!-- テキスト入力部 --> <p>身分 <input type="radio">会社員 <!-- ラジオボタン --> <input type="radio">学生 <input type="radio">主婦 <input type="radio">無職 </p> <p>年齢: <select> <!-- 選択 --> <option>10歳以下</option> <option>10~20歳</option> <option>20~30歳</option> <option> それ以上</option> </select> </p> ご要望: <p> <textarea rows=5 cols=30> <!-- テキストエリア --> </textarea> </p> <p><input type="submit" value="送信"></p> <!-- 送信ボタン --> </form>
いろいろ書きましたが、これをブラウザで見ると下のようになります。
フォームを作る
ではDjangoを使ってフォームを実装してみます。
どこを変更するか
今回はdetail.html
を変更していきます。前回までで作ったdetail.html
は下のようでした。
<!DOCTYPE html> <html> <head> <meta charset='utf-8'> </head> <body> <h1>{{ question.question_text }} </h1> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </body> </html>
これを下のように変更します。
<!DOCTYPE html> <html> <head> <meta charset='utf-8'> </head> <body> <h1>{{ question.question_text }} </h1> <form action="{% url 'polls:vote' question.id %}" method="post"> {% csrf_token %} {% for choice in question.choice_set.all %} <p> <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}"> <label for="choice{{ forloop.counter }}"> {{ choice.choice_text }} </label> {% endfor %} </p> <p> <input type="submit" value="Vote"> </p> </form> </body> </html>
だいぶいろいろ付け加わりました。
formタグの書き方
8行目を見てみると、ここでフォームの定義とアクションが設定されています。アクションには前回の記事で説明したように、{% url %}
タグを用いています。しかしその中身は前回説明したものとは少し異なっています。'polls:vote'とは何でしょうか?これはpollsがアプリケーションの名前で、voteがname=
によって識別された名前を表しています。pollsアプリケーションを認識させるためにはもうひと手間必要ですが、これはurls.py
を編集するところで解説します。
もうひとつ重要なのが、methodの欄です。データベースに変更があるときには必ず"post"にする必要があります。
forループ
HTML内でのforループが再び出てきました。もう見慣れてきたかもしれませんが、こちらも今までとは異なる要素が入ってきています。それはforloop.count
です。これはforループが何回回ったかをあらわすものです。
ビューを編集する
detail.htmlを書き換えましたので、ビューもこれを正しく表示できるように変更しましょう。detail.htmlにはVoteボタンがあるので、これが押されたときの遷移画面も考えなくてはいけません。
views.py
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) def detail(request, question_id): question = Question.objects.get(pk=question_id) return render(request, 'polls/detail.html', {'question' : 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 did not select a choice', }) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', \ args=(question.id,))) def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question' : question})
vote関数について説明をします。
get_object_or_404(Question, pk=question_id)
これは、Questionオブジェクトの中からpk要素がquestion_idに等しいものがある場合にはそれを取得し、ない場合には「404 ページが見つかりませんでした」の表示を行います。
HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
reverse関数というものが登場しています。これは{% url %}
タグと似ていて、URLのハードコードを避けることができます。'polls:result'を探し出して引数としてquestion_idを渡します。
Voteボタンが押されたらHttpResponseRedirectが呼ばれてresultsに結び付けられているページへ遷移する仕組みになっています。
resultsビューはすぐ下に定義されていて、results.htmlに結び付けられています。ではこのページについても見ておきましょう。
results.htmlの中身
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}--{{ choice.votes }} vote</li> {% endfor %} </ul> <a href="{% url 'polls:detail' question.id %}">Vote Again?</a> </body> </html>
ここに関しては新しい要素というのは出てきてはいません。Vote Againにリンクが結び付けられていて、質問ページに戻れるようになっています。
urls.pyを編集する
ではこれまでの編集で新たに必要になった要素をurls.py
に付け足していきます。
urls.py
from django.urls import path from . import views app_name = 'polls' urlpatterns = [ path('', views.index, name='index'), path('<int:question_id>/', views.detail, name='detail'), path('<int:question_id>/results/', views.results, name='results'), path('<int:question_id>/vote', views.vote, name='vote'), ]
urlpatternだけではなく、app_nameという要素が付け加わったことに注目してください。HTMLファイルを編集していた時に'polls:results'のような表現が現れていたことを覚えているでしょうか?この'polls'がapp_nameに対応しています。
お疲れ様です。これで完成です。今回の記事では、実際にpollsアプリケーションで投票操作を実装しました。