:
<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>
A quick rundown:
- The above template displays a radio button for each question choice. The
valueof each radio button is the associated question choice’s ID. The
nameof each radio button is
"choice". That means, when somebody selects one of the radio buttons and submits the form, it’ll send the POST data
choice=#where # is the ID of the selected choice. This is the basic concept of HTML forms.
- We set the form’s
actionto
{% url 'polls:vote' question.id %},indicates how many times the
fortag has gone through its loop
-.
Now, let’s create a Django view that handles the submitted data and does something with it. Remember, in Tutorial 3, we created a URLconf for the polls application that includes this line:
url(r'^(?P<question from django.core.urlresolvers import reverse from polls.models import Choice, Question # ... def vote(request, question_id): p = get_object_or_404(Question, pk=question_id) try: selected_choice = p.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): # Redisplay the question voting form. return render(request, 'polls/detail.html', { 'question':('polls:results', args=(p.id,)))
This code includes a few things we haven’t covered yet in this tutorial:
request.POSTis a dictionary-like object that lets you access submitted data by key name. In this case,
request.POST['choice']returns the ID of the selected choice, as a string.
request.POSTvalues are always strings.
Note that Django also provides
request.GETfor accessing GET data in the same way – but we’re explicitly using
request.POSTin our code, to ensure that data is only altered via a POST call.
request.POST['choice']will raise
KeyErrorif
choicewasn’t provided in POST data. The above code checks for
KeyErrorand redisplays the question form with an error message if
choiceisn’t given.
After incrementing the choice count, the code returns an
HttpResponseRedirectrather than a normal
HttpResponse.
HttpResponseRedirecttakes a single argument: the URL to which the user will be redirected (see the following point for how we construct the URL in this case).
As the Python comment above points out, you should always return an
HttpResponseRedirectafter successfully dealing with POST data. This tip isn’t specific to Django; it’s just good Web development practice.
We are using the
reverse()function in the
HttpResponseRedirectconstructoris the value of
p.id. This redirected URL will then call the
'results'view to display the final page.
As mentioned in Tutorial 3,
request is.
Use generic views: Less code is better¶. We will:
- Convert the URLconf.
- Delete some of the old, unneeded views.
- Introduce new views based on Django’s generic views.
Read on for details..<question_id>\d+)/vote/$', views.vote, name='vote'), )
Note that the name of the matched pattern in the regexes of the second and third
patterns has changed from
<question_id> to
<pk>.attribute.
- The
DetailViewgeneric view expects the primary key value captured from the URL to be called
"pk", so we’ve changed
question_idto
pkfor just.