1、现在在我们先前的polls/detail.html文件中添加一个表单元素:polls/templates/polls/detail.html
2、<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>
3、简要说明:上面的模板显示一系列单选按钮,按钮的值是选项的ID,按钮的名字是字符串"choice"。这意味着,当你选择了其中某个按钮,并提交表单,一个包含数据choice=#的POST请求将被发送到指定的url,#是被选择的选项的ID。这就是HTML表单的基本概念。如果你有一定的前端开发基础,那么form标签的action属性和method属性你应该很清楚它们的含义,action表示你要发送的目的url,method表示提交数据的方式,一般分POST和GET,更多的解释就不是本教程干的事情了,你需要补课。forloop.counter是DJango模板系统管理专门提供的一个变量,用来表示你当前循环的次数,一般用来给循环项目添加有序数标。由于我们发送了一个POST请求,就必须考虑一个跨站请求伪造的问题,简称CSRF(具体含义请百度)。Django为你提供了一个简单的方法来避免这个困扰,那就是在form表单内添加一条{% csrf_token %}标签,标签名不可更改,固定格式,位置任意,只要是在form表单内。但是(译者注),这个方法对form表单的提交方式方便好使,但是如果是用ajax的方式提交数据,那么就很费劲了。个人认为不如直接在Django配置中关闭这个看似有作用,其实然并卵的CSRF得了。
4、现在,让我们创建一个处理提交过来的数据的视图。前面我们已经写了一个“占坑”的vote视图的url:polls/urls.pyurl(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
5、以及“占坑”的vote视图函数,我们把坑填起来:polls/views.py
6、from django.shortcuts import get_object_or_404, re荏鱿胫协nderfrom django.http import HttpResponseRedirect, HttpResponsefrom django.urls import reversefrom .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): # 发生choice未找到异常时,重新返回表单页面,并给出提示信息 return render(request, 'polls/detail.html', { 'question': question, 'error_message': "You didn't select a choice.", }) else: selected_choice.votes += 1 selected_choice.save() # 成功处理数据后,自动跳转到结果页面,防止用户连续多次提交。 return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
7、有些新的东西,我们要解释一下:request.POS哌囿亡噱T是一个类似字典的对象,允许你通过键名访问提交的数据。本例中,request.POST[’choice’]返回被选择选剐疫柩缓项的ID,并且值的类型永远是string字符串,那怕它看起来像数字,记住了!!!!同样的,你也可以用类似的手段获取GET请求发送过来的数据,一个道理。request.POST[’choice’]有可能触发一个KeyError异常,如果你的POST数据里没有提供choice键值,在这种情况下,上面的代码会返回表单页面并给出错误提示。译者注:通常我们会给个默认值,防止这种异常的产生,例如:request.POST[’choice’,None],一个None解决所有问题。在选择计数器加一后,返回的是一个HttpResponseRedirect而不是先前我们常用的HttpResponse。HttpResponseRedirect需要一个参数:重定向的URL。这里有一个建议,当你成功处理POST数据后,应当保持一个良好的习惯,始终返回一个HttpResponseRedirect。这不仅仅是对Django而言,它是一个良好的WEB开发习惯。我们在上面HttpResponseRedirect的构造器中使用了一个reverse()函数。它能帮助我们避免在视图函数中硬编码URL。它首先需要一个我们在URLconf中指定的name,然后是传递的数据。例如'/polls/3/results/',其中的3是某个question.id的值。重定向后将进入'polls:results'对应的视图,并将question.id传递给它。白话来讲,就是把活扔给另外一个路由对应的视图去干。