四、Writing your first Django app, part 4
写一个简单的表单
继续Part 3的例子
1.修改 polls/detail.html
模版文件,增加form元素
{ { poll.question }}
{% if error_message %}{ { error_message }}
{% endif %}
注意事项:
- 增加一些 radio 按钮,按钮的value是choice.id的值,提交的时候通过post中的choice值来处理
- 使用 method="post" 方法
- 提交的地址是
{% url 'polls:vote' poll.id %}
- forloop.counter 是循环计数变量
- 使用
{% csrf_token %}
避免跨站攻击
2.增加处理post数据的vote部分
完善polls/views.py
from django.shortcuts import get_object_or_404, renderfrom django.http import HttpResponseRedirect, HttpResponsefrom django.core.urlresolvers import reversefrom polls.models import Choice, Poll# ...def vote(request, poll_id): p = get_object_or_404(Poll, pk=poll_id) try: selected_choice = p.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): # Redisplay the poll voting form. return render(request, 'polls/detail.html', { 'poll': p, '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=(p.id,)))
代码解读:
- 使用
request.POST['choice']
的方法访问 POST 数据 - 如果在字典访问中找不到 choice key,抛出 KeyError 异常
- 尽量使用
HttpResponseRedirect
代替HttpResponse
- 通过使用 reverse()方法来避免在视图中写入硬编码的网址
3.完善结果显示的页面 results()
def results(request, poll_id): poll = get_object_or_404(Poll, pk=poll_id) return render(request, 'polls/results.html', {'poll': poll})
4.建立polls/results.html
模版文件
{ { poll.question }}
- {% for choice in poll.choice_set.all %}
- { { choice.choice_text }} -- { { choice.votes }} vote{ { choice.votes|pluralize }} {% endfor %}
使用通用视图来改写上面的例子
- ListView
- DetailView
1. 在urls.py中的设置
url(r'^$', views.IndexView.as_view(), name='index'),url(r'^(?P\d+)/$', views.DetailView.as_view(), name='detail'),
2. 视图中的写法
from django.shortcuts import get_object_or_404, renderfrom django.http import HttpResponseRedirectfrom django.core.urlresolvers import reversefrom django.views import genericfrom polls.models import Choice, Pollclass IndexView(generic.ListView): template_name = 'polls/index.html' context_object_name = 'latest_poll_list' def get_queryset(self): """Return the last five published polls.""" return Poll.objects.order_by('-pub_date')[:5]class DetailView(generic.DetailView): model = Poll template_name = 'polls/detail.html'class ResultsView(generic.DetailView): model = Poll template_name = 'polls/results.html'def vote(request, poll_id): ....
3.解读
- pk作为主键
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
- model 表的名称
- template_name 模版的名称
- context_object_name 自定义模版中的变量名称