【Django】はじめてのDjangoアプリ第8回

django

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

Writing your first Django app, part 4 | Django documentation
The web framework for perfectionists with deadlines.

前回はビューの追加を行いました。

今回はフォームを設置していきます。

最小限のフォーム

前回のチュートリアルの投票詳細テンプレート (「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 で述べたように、requestHttpRequest オブジェクトです。 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

コメント

タイトルとURLをコピーしました