PythonのWEBフレームワークDjangoを利用したアプリケーションの公式テュートリアルに沿ったWEBアプリケーション作成のメモ第8回です。

前回はビューの追加を行いました。
今回はフォームを設置していきます。
最小限のフォーム
前回のチュートリアルの投票詳細テンプレート (「polls/detail.html」) を更新して、テンプレートに HTML フォーム要素が含まれるようにしましょう。
▼「polls/templates/polls/detail.html」
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset>
<legend><h1>{{ question.question_text }}</h1></legend>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% 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 %}
</fieldset>
<input type="submit" value="Vote">
</form>
▼http://localhost:8000/polls/1/

簡単な概要:
🟢上記のテンプレートには、質問の選択肢ごとにラジオ ボタンが表示されます。各ラジオ ボタンの値は、関連付けられた質問の選択肢の ID です。各ラジオボタンの名前は「choice」です。つまり、誰かがラジオ ボタンの 1 つを選択してフォームを送信すると、POST データchoice=# が送信されます。# は選択された選択肢の ID です。これが HTML フォームの基本的な概念です。
🟢フォームのアクションを {% url ‘polls:vote’ question.id %} に設定し、method=’post’ を設定します。このフォームを送信するとサーバー側のデータが変更されるため、(method=’get’ ではなく) method=’post’ を使用することは非常に重要です。サーバー側でデータを変更するフォームを作成する場合は、常に、method=’post’ を使用します。このヒントは Django に固有のものではありません。これは一般的に Web 開発の良い習慣です。
🟢forloop.counter は、for タグがループを通過した回数を示します。
🟢POST フォームを作成しているため (データを変更する可能性があります)、クロスサイト リクエスト フォージェリについて心配する必要があります。ありがたいことに、Django にはそれを防ぐための便利なシステムが付属しているため、あまり心配する必要はありません。つまり、内部 URL を対象とするすべての POST フォームは、{% csrf_token %} テンプレート タグを使用する必要があります。
次に、送信されたデータを処理し、それに対して何らかの処理を行う Django ビューを作成しましょう。チュートリアル 3 で、次の行を含む世論調査アプリケーションの URLconf を作成したことを思い出してください。
▼「polls/urls.py」
path("<int:question_id>/vote/", views.vote, name="vote"),
また、vote() 関数のダミー実装も作成しました。実際のバージョンを作成しましょう。以下をpolls/views.pyに追加します。
▼「polls/views.py」に追記
※冒頭部を編集
from django.db.models import F
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.template import loader
from django.urls import reverse
from .models import Choice, Question
※「vode()」を編集
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):
# Redisplay the question voting form.
return render(
request,
"polls/detail.html",
{
"question": question,
"error_message": "You didn't select a choice.",
},
)
else:
selected_choice.votes = F("votes") + 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse("polls:results", args=(question.id,)))
このコードには、このチュートリアルでまだ説明していないことがいくつか含まれています。
🟢request.POST は、キー名によって送信されたデータにアクセスできる辞書のようなオブジェクトです。この場合、request.POST[‘choice’] は選択された選択肢の ID を文字列として返します。 request.POST 値は常に文字列です。
Django は、同じ方法で GET データにアクセスするための request.GET も提供していることに注意してください。ただし、データが POST 呼び出し経由でのみ変更されるようにするために、コード内で明示的に request.POST を使用しています。
🟢POST データに選択肢が指定されていない場合、request.POST[‘choice’] は KeyError を発生させます。上記のコードは KeyError をチェックし、選択肢が与えられない場合はエラー メッセージを含む質問フォームを再表示します。
🟢F(‘votes’) + 1 は、データベースに投票数を 1 増やすように指示します。
🟢選択数を増加した後、コードは通常の HttpResponse ではなく HttpResponseRedirect を返します。 HttpResponseRedirect は、ユーザーのリダイレクト先となる URL という 1 つの引数を取ります (この場合の URL の構築方法については、次の点を参照してください)。
🟢上記の Python コメントが指摘しているように、POST データを正常に処理した後は、常に HttpResponseRedirect を返す必要があります。このヒントは Django に固有のものではありません。これは一般的に Web 開発の良い習慣です。
🟢この例では、HttpResponseRedirect コンストラクターで reverse() 関数を使用しています。この関数は、ビュー関数で URL をハードコーディングする必要を回避するのに役立ちます。制御を渡すビューの名前と、そのビューを指す URL パターンの変数部分が指定されます。この場合、チュートリアル 3 で設定した URLconf を使用すると、この reverse() 呼び出しは次のような文字列を返します。
"/polls/3/results/"ここで、3 は question.id の値です。このリダイレクトされた URL は「結果」ビューを呼び出して、最終ページを表示します。
チュートリアル 3 で述べたように、requestは HttpRequest オブジェクトです。 HttpRequest オブジェクトの詳細については、リクエストと応答のドキュメントを参照してください。
誰かが質問に投票すると、vote() ビューは質問の結果ページにリダイレクトされます。そのビューを書いてみましょう:
▼「polls/view.py」を編集
※「results()」を編集
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/results.html", {"question": question})
これは、チュートリアル 3 のdetail() ビューとほぼ同じです。唯一の違いは、テンプレート名です。この冗長性は後で修正します。
次に、polls/results.html テンプレートを作成します。
▼「polls/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>
次に、ブラウザで /polls/1/ にアクセスし、質問に投票してください。投票するたびに更新される結果ページが表示されます。選択肢を選択せずにフォームを送信すると、エラー メッセージが表示されます。
▼http://localhost:8000/polls/1/

適当に選択して「Vote」ボタンを押下。
▼http://localhost:8000/polls/1/results/ へリダイレクト

結果が表示されました。
「Vote again?」のリンクをクリックすると、
http://localhost:8000/polls/1/ に移動します。
選択肢を選ばずに「Vote」ボタンを押下すると
エラーが表示されます。

今回は以上です。次回はこの続きを予定しています。
- 0
- 0
- 0
- 0



コメント