设计简单表单 form
更新/polls/templates/polls/detail.html,包含一个HTML <form> 元素:
<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>
快速解释:
上述模板显示一个为每个question choice提供一个radio按钮。每个radio按钮的值与question choice的ID关联。每个radio按钮的名字是‘choice’。这意味着,当有人选择一个radio按钮并提交form,这将发送一个POST数据choice=#,这里#是所选choice的ID。这是HTML form的基本概念。form的method设置为‘post’post很重要。
forloop.counter表示该循环中for tag已经使用的次数。
既然已经生成了一个POST表单,需要考虑跨域伪造请求问题。简而言之,所有POST表单在内部URLs的定位必须使用{% csrf_token %}模板标签。
polls/urls.py:
path('<int:question_id>/vote/', views.vote, name='vote'),
编辑polls/views.py:
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from .models import Choice, 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):
# 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 += 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,)))
说明:
1、request.POST为一个类似字典的对象,访问由key名字提交的数据。这种场景下,request.POST['choice']返回选择choice的ID,request.POST的值总是字符串形式的。
2、POST成功之后采用HttpResponseRedirect返回而不是HttpResponse.HttpResponseRedirect,是一种好的web开发实践。
3、resverse()函数帮助避免视图函数中的硬编码。它采用视图的名字作为入参。
使用通用视图:Less code is better
参考:
https://docs.djangoproject.com/en/2.0/intro/tutorial04/