Tutorial 4. We have finally entered the final tutorial. We will finish a voting application called polls.
Describe the template of the detail page as follows.
detail.html ######
<h1>{{ poll.question }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="/polls/{{ poll.id }}/vote/" method="post">
{% csrf_token %}
{% for choice in poll.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}"
value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>
It contains some words that you see for the first time.
You can imagine this by name, but it's a value defined on the views.py side, so you don't have to remember it separately.
A cliché that means the number of times a loop has been turned. It's easy to remember because it's just the meaning.
So-called CSRF measures. This seems to be the most important. If you want to send a POST method to your site, you should consider it mandatory. So what is CSRF? So I googled. http://e-words.jp/w/CSRF.html For convenience of using this, views.py will also be edited.
views.py ####
from django.template import RequestContext #RequestContext seems to be a subclass of Context
# ...
def detail(request, poll_id):
pobject = get_object_or_404(Poll, pk=poll_id) #pk is an abbreviation for Primary Key. Reserved word?
return render_to_response('polls/detail.html', {'poll': pobject},
context_instance=RequestContext(request)) # context_A new instance has been added. Maybe reserved words
Also implement the vote part.
from django.shortcuts import get_object_or_404, render_to_response
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse
from django.template import RequestContext
from polls.models import Choice, Poll
#...
def vote(request, poll_id):
pobject = get_object_or_404(Poll, pk=poll_id)
try:
selected_choice = pobject.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
return render_to_response('polls/detail.html', {
'poll': pobject,
'error_message': "First choose the option",
}, context_instance=RequestContext(request))
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls.views.results', args=(pobject.id,)))
Here are some words I haven't seen before, so I'll summarize them.
Received the data that has been POSTed. You can retrieve the value according to the name by doing request.POST ['name']. I feel that it is written as $ _POST in any language.
A subclass of Context. You have to put the HttpRequest object in the first argument here. Here, the first argument request of the view function vote is entered as it is (the accessed HttpRequest is probably automatically assigned to the first argument of the view function).
The name (probably fixed) to use when returning render_to_response with a shortcut. Assign an HttpRequest object.
render_to_response('for/your/template',{'name':value},context_instance)
Do you feel that you specify the template in the first argument, put the data in the second argument, and pass the data to the template in the request of the third argument?
Update the set database. Here, the value of selected_choice.votes (data name defined in models.py) is incremented by one and then overwritten.
I'm not sure from that alone, so if you dig a little deeper, This selected_choice seems to refer to the data with the POSTed'choice'value as the Primary Key from the choice_set. So, this choice_set is a set of choices obtained from pobject (the way to write hoge_set seems to be a cliché. For details, see Tutorial 1 in tutorial01.html)). Reviewing the template, the value of the "choice" radio button is "{{choice.id}}", and what is this id?
python manage.py sql polls
Can be confirmed at
"id" integer NOT NULL PRIMARY KEY
The data looks like this (id seems to be automatically generated even if it is not defined in models.py). Well, in short, it's like what number of choice.
In other words
# def vote….
selected_choice.votes += 1
selected_choice.save()
In the part of, the data with the value of the selected choice as id is added and saved. If you check the template, this id will be the value of the radio button as it is, and as a result, the data of the item selected by the radio button will be updated.
I'm surprised that it's been so long, but that's probably the process flow (please tell me if it's different).
In previous programs, it was HttpResponse exclusively, but here Redirect is attached. In the first argument reverse, the contents are
’/polls/[id]/results/‘
It is converted and returned as. Specify the redirect destination? args seems to be an argument to bring to the redirect destination (can it be put in poll_id of the results function?). There's only one content here, but don't forget to add a comma! It seems to be the rule of the Web to redirect when POST is successful.
So, next, we will design the redirect destination results.
def results(request, poll_id):
pobject = get_object_or_404(Poll, pk=poll_id)
return render_to_response('polls/results.html', {'poll': pobject})
Also make a template.
results.html ######
<h1>{{ poll.question }}</h1>
<ul>
{% for choice in poll.choice_set.all %}
<li>{{ choice.choice }} -- {{ choice.votes }}Vote</li>
{% endfor %}
</ul>
<a href="/polls/{{ poll.id }}/">Do you still vote?</a>
The above is the summary of the tutorial. However, in this case, I often use shortcuts. That wouldn't be a learning experience, so I rewrote it to one that doesn't use shortcuts.
views.py ######
from polls.models import Poll,Choice
from django.http import HttpResponse,HttpResponseRedirect
from django.template import Context,loader,RequestContext
from django.core.urlresolvers import reverse
from django.http import Http404
def index(req):
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
temp = loader.get_template('polls/index.html')
contxt = Context({
'latest_poll_list':latest_poll_list
})
return HttpResponse(temp.render(contxt))
def detail(req,poll_id):
try:
pobject = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
temp = loader.get_template('polls/detail.html')
contxt = RequestContext(req,{
'poll':pobject
})
return HttpResponse(temp.render(contxt))
def results(req,poll_id):
try:
pobject = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
temp = loader.get_template('polls/results.html')
contxt = Context({
'poll':pobject
})
return HttpResponse( temp.render(contxt) )
def vote(req,poll_id):
try:
pobject = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
try:
selected_choice = pobject.choice_set.get(pk=req.POST['choice'])
except (KeyError,Choice.DoesNotExist):
temp = loader.get_template('polls/detail.html')
contxt = RequestContext(req,{
'poll':pobject,
'error_message':"You have to select choice!"
})
return HttpResponse(temp.render(contxt))
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect( reverse('polls.views.results',args=(pobject.id,) ) )
Ichiou operation is also confirmed.
What I struggled with was where to put the context_instance, which is included as the third argument in the render_to_response of detail and vote. Solved by writing RequestContext (request, {'name': value}).
Even so, I wrote the same thing many times and it's not cool. I've managed to understand the flow, and maybe it's time to use the shortcut.
Recommended Posts