Django官方文档学习笔记:Tutorial: Part 4
继续折腾这个投票应用,本章主要讲如何处理表单。一、写一个表单
修改原来的detail.html模板("
polls/
templates/polls/detail.html
"):
forloop.counter for循环的次数
<
h1
>
{{ poll.question }}
</
h1
>
{% if error_message %} < p >< strong > {{ error_message }} </ strong ></ p > {% endif %}
< form action ="{% url 'polls:vote' poll.id %}" 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_text }} </ label >< br />
{% endfor %}
< input type ="submit" value ="Vote" />
</ form >
{% if error_message %} < p >< strong > {{ error_message }} </ strong ></ p > {% endif %}
< form action ="{% url 'polls:vote' poll.id %}" 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_text }} </ label >< br />
{% endfor %}
< input type ="submit" value ="Vote" />
</ form >
{% csrf_token %} 避免别的网站伪造post请求数据。
如代码所描述的,post之后会跳到vote去,修改poll应用的views.py(" polls/views.py")实现一下vote响应方法。
#
Create your views here.
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponse, HttpResponseRedirect
from django.core.urlresolvers import reverse
from polls.models import Poll, Choice
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):
return render(request, ' polls/detail.html ' , {
' poll ' : p,
' error_message ' : " You din'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 根据key访问post提交的数据。同理get请求则使用request.GET
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponse, HttpResponseRedirect
from django.core.urlresolvers import reverse
from polls.models import Poll, Choice
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):
return render(request, ' polls/detail.html ' , {
' poll ' : p,
' error_message ' : " You din'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,会爆出KeyError异常。
HttpResponseRedirect 页面重定向。避免post多次。
reverse() 调用url链接,避免硬编码。
创建results模板文件( " polls/ templates/polls/results.html ")。
<
h1
>
{{ poll.question }}
</
h1
>
< ul >
{% for choice in poll.choice_set.all %}
< li > {{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }} </ li >
{% endfor %}
</ ul >
< a href ="{% url 'polls:detail' poll.id %}" > Vote again? </ a >
< ul >
{% for choice in poll.choice_set.all %}
< li > {{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }} </ li >
{% endfor %}
</ ul >
< a href ="{% url 'polls:detail' poll.id %}" > Vote again? </ a >
二、使用通用视图:减少代码
在web开发中,从数据库查询,并渲染模板页面到显示,这是个很常见的情况。Django提供了一个用来快速生成视图的“generic views”系统。可以将通用的ListView、DetailView的渲染通过它在URLconf中完成。
修改URLconf
修改poll应用的urls配置文件("
polls/urls.py"):
修改views
from
django.conf.urls
import
patterns, url
from django.views.generic import ListView
from django.views.generic.detail import DetailView
from polls.models import Poll
urlpatterns = patterns( '' ,
# ex: /polls/
url(r ' ^$ ' , ListView.as_view(queryset = Poll.objects.order_by( ' -pub_date ' )[: 5 ],
context_object_name = ' latest_poll_list ' ,
template_name = ' polls/index.html ' ), name = ' index ' ),
# ex: /polls/5/
url(r ' ^(?P<pk>\d+)/$ ' , DetailView.as_view(
model = Poll,
template_name = ' polls/detail.html '
), name = ' detail ' ),
# ex: /polls/5/results/
url(r ' ^(?P<pk>\d+)/results/$ ' , DetailView.as_view(
model = Poll,
template_name = ' polls/results.html '
), name = ' results ' ),
# ex: /polls/5/vote/
url(r ' ^(?P<poll_id>\d+)/vote/$ ' , ' polls.views.vote ' , name = ' vote ' ),
)
from django.views.generic import ListView
from django.views.generic.detail import DetailView
from polls.models import Poll
urlpatterns = patterns( '' ,
# ex: /polls/
url(r ' ^$ ' , ListView.as_view(queryset = Poll.objects.order_by( ' -pub_date ' )[: 5 ],
context_object_name = ' latest_poll_list ' ,
template_name = ' polls/index.html ' ), name = ' index ' ),
# ex: /polls/5/
url(r ' ^(?P<pk>\d+)/$ ' , DetailView.as_view(
model = Poll,
template_name = ' polls/detail.html '
), name = ' detail ' ),
# ex: /polls/5/results/
url(r ' ^(?P<pk>\d+)/results/$ ' , DetailView.as_view(
model = Poll,
template_name = ' polls/results.html '
), name = ' results ' ),
# ex: /polls/5/vote/
url(r ' ^(?P<poll_id>\d+)/vote/$ ' , ' polls.views.vote ' , name = ' vote ' ),
)
到此,可以把原视图("
polls/views.py")中的index()、detail()、results()方法删掉了。
这里使用了ListView、DetailView。需要注意的是,DetailView使用“ pk”去匹配url中的id。
DetailView、ListView默认分别调用“<app_name>/<model_name>_detail.html”、“<app_name>/<model_name>_list.html”模板,可以通过“ template_name”参数指定特定的模板。
ListView默认生成的传递给模板的上下文变量为“<model_name>_list”,可通过“ context_object_name”参数来指定传输变量。