【译】本身动手写Django app,第四部分【全剧终】

原文地址:https://docs.djangoproject.com/en/1.4/intro/tutorial04/ html

这个教程是从教程3剩下的地方开始的。咱们继续网络调查应用程序并将关注简单的表单处理和精简咱们的代码。 python

1、写一个简单的表单 数据库

让咱们从上个教程中更新咱们的调查详细模板(“polls/detail.html”),这样模板就包含一个HTML<form>元素: django

<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>
快速摘要:

    上面的模板在每一个调查选择上显示一个单选按钮。每一个单选按钮的值和调查选择的ID相关联。每一个单选按钮的名字就是“choice”。这就是说,当有人选择一个单选按钮而后提交表单,你将发送POST数据choice=3。这就是HTML表单101; 浏览器

    咱们把表单的动做指向/polls/{{ poll.id }}/vote/,咱们设置method="post"。用method="post"(相反的是method="get")很重要,由于提交这个表单的动做会改变数据的服务器端。无论何时你建立了一个改变数据服务器端的表单,使用method="post"。这个小知识不只仅对Django有用。这是好的网络开发经验; 缓存

    forloop.counter暗示for标签在它的循环中经历了多少次; 服务器

    既然咱们建立了一个POST表单(它有修改数据的影响),咱们须要担忧跨站点请求伪造。可是高兴的是,你不须要担忧太多,由于Django提供了一个很容易使用的系统来抵御它。简而言之,内部URLs针对的全部POST表单应该用{% csrf_token %}模板标签; 网络

{% csrf_token %}标签须要来自请求对象的信息,它一般从模板环境不可接触。为了修复这个,咱们须要对detail视图作小的调整,让它看起来像下面同样: app

from django.template import RequestContext
# ...
def detail(request, poll_id):
    p = get_object_or_404(Poll, pk=poll_id)
    return render_to_response('polls/detail.html', {'poll': p},
                               context_instance=RequestContext(request))
它如何工做的细节在RequestContext文档中已经解释了。

如今,让咱们建立一个处理提交数据的Django视图并对它作一些事情。记住,在教程3中,咱们为调查应用程序建立一个URLconf包含了下面的一行: 框架

(r'^(?P<poll_id>\d+)/vote/$', 'vote'),
咱们也建立了一个假的实现vote()函数。让咱们建立一个真的版本,在polls/views.py中增长下面:
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):
    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_to_response('polls/detail.html', {
            'poll': p,
            'error_message': "You didn't select a choice.",
        }, context_instance=RequestContext(request))
    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.views.results', args=(p.id,)))
这个代码包含了一些咱们在这个教程中尚未设计到的东西:

    request.POST是一个像字典的对象让你能够按照键名访问提交的数据。这种状况下,request.POST['choice']返回选中的选择的ID做为一个字符串。request.POST的值老是一个字符串。注意Django老是用相同的的方式提供request.GET访问GET的数据——可是咱们在咱们的代码中明确使用request.POST来确保数据经过POST调用改变了。

    若是POST数据没有提供choice,request.POST['choice']会产生KeyError。上面的代码检查KeyError,若是choice没有,就会从新显示一个带有错误信息的调查表单;

    在这个例子中,咱们在HttpResponseRedirect容器中用reverse()函数。这个函数帮助避免在视图函数中处理硬编码。这是考虑到的视图名称,咱们想经过控制和可变部分的URL模式来指出这个视图。在这种状况下,用我么你在教程3中建立的URLconf,这个reverse()函数将会返回一个像下面的字符串:

'/polls/3/results/'
——这里的3是p.id的值。这个重定向URL会调用'results'视图来显示最终的页面。注意这儿你须要用视图的全名(包括前缀)。

在教程3中已经提到了,request是一个HttpResponse对象。更多关于HttpResponse对象,请看请求和响应文档。

当有人投票了一个调查以后,vote()视图重定向调查结果页面。让咱们写这个视图:

def results(request, poll_id):
    p = get_object_or_404(Poll, pk=poll_id)
    return render_to_response('polls/results.html', {'poll': p})
这基本和教程3中的detail()视图是彻底同样。惟一的区别就是名字。咱们以后会修复这个冗余。

如今,建立一个results.html模板:

<h1>{{ poll.question }}</h1>

<ul>
{% for choice in poll.choice_set.all %}
    <li>{{ choice.choice }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>

<a href="/polls/{{ poll.id }}/">Vote again?</a>
如今,在你的浏览器中查看/polls/1/而后再调查程序中投票。你应该看到一个更新每次你投票的结果页面。若是你没有作出选择就提交了表单,你应该能看到错误信息。

2、使用通用视图:代码越少越好

detail()(来自教程3)和results()视图很蠢很简单——就像上面提到的同样,冗余。index()(来自教程3)视图相似显示一系列调查。

这些视图表示基本网络开发的常例:根据URL传递的参数从数据库得到数据,载入模板,而后返回提供的模板。由于这是共同的,Django提供一个快捷方式叫作“通用视图”系统。

通用视图把通常的模式抽象到你不须要写python代码的程度。

让咱们用通用视图系统转换咱们的调查程序,这样咱们就能删掉许多咱们的代码。咱们只要采起一些步骤来实现这个转换。咱们会:

    1.转换URLconf;

    2.删除一些老的不须要的视图;

    3.修复处理新的视图的URL;

看看详情。

(为何搅乱代码?:一般来说,当写一个Django应用程序时,你须要估计通用视图是否适用于你的问题,你将在开始用它们而不是半途重构你的代码。可是这个教程直到如今的目的关注“硬方式”写视图,关注核心理念。在你开始用计算器以前你应该了解基本的数学。)

首先,打开poll/urls.py的URLconf。根据到目前的教程,它看起来像这样:

from django.conf.urls import patterns, include, url

urlpatterns = patterns('polls.views',
    url(r'^$', 'index'),
    url(r'^(?P<poll_id>\d+)/$', 'detail'),
    url(r'^(?P<poll_id>\d+)/results/$', 'results'),
    url(r'^(?P<poll_id>\d+)/vote/$', 'vote'),
)
把它改为下面这样:
from django.conf.urls import patterns, include, url
from django.views.generic import DetailView, ListView
from polls.models import Poll

urlpatterns = patterns('',
    url(r'^$',
        ListView.as_view(
            queryset=Poll.objects.order_by('-pub_date')[:5],
            context_object_name='latest_poll_list',
            template_name='polls/index.html')),
    url(r'^(?P<pk>\d+)/$',
        DetailView.as_view(
            model=Poll,
            template_name='polls/detail.html')),
    url(r'^(?P<pk>\d+)/results/$',
        DetailView.as_view(
            model=Poll,
            template_name='polls/results.html'),
        name='poll_results'),
    url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
)
在这里咱们使用了两个通用视图:ListView和DetailView。分别地,这两个视图抽象“显示一些列对象”和“显示一个对象类型的详细页面”的概念。

    每一个通用视图须要知道它做用的模型。这是用模型参数提供的;

    DetailView通用视图期待从URL中捕获的第一个关键字的值(被称做“px”),所以咱们为了通用视图把poll_id改为px;

    咱们已经给结果视图增长了一个名字poll_results,这样咱们以后有一种提到它的URL方式(详细信息请查看命名URL模式文档)。这里咱们也从django.conf.urls调用url()函数。当你提供一个像这样模式的名字的时候,使用url()是个好习惯。

默认状况下,DetailView通用视图用一个叫作<app name>/<model name>_detail.html模板。在咱们的例子中,它用一个模板“polls/poll_detail.html”。template_name参数是用来告诉Django一个明确的模板名字而不是一个自动生成的默认模板名字。咱们也规定resultstemplate_name的列表视图——这确保结果视图和细节视图在显示的时候有不一样的外观,即便他们幕后都是DetailView。

相似地,ListView通用视图用一个叫作<app name>/<model name>_list.html的默认模板,咱们用template_name告诉ListView用咱们存在的polls/index.html模板。

在教程的前面部分,已经提供了带有上下文的模板,它包含了poll和latest_poll_list环境变量。对DetailView来讲,poll变量是自动提供的——由于咱们用一个Django模型(Poll),Django能决定环境变量的合适名字。然而,对于ListView来讲,自动生成的上下文变量是poll_list。覆写这个,咱们提供了context_object_name选项来明确咱们想用latest_poll_list。做为一个可选的方式,你能够改变你的模板来匹配新的默认的环境变量——可是告诉Django用你想用的变量更容易。

你如今能够从polls/views.py中删除index(),detail()和results()。咱们再也不须要他们了——他们已经被通用视图代替了。

最后要作的是解决通用视图的使用时URL的处理。在上面的投票视图中,咱们用reverse()函数避免咱们的URLs硬编码。如今咱们已经切换到通用视图,咱们须要改变reverse()调用指向咱们新的通用视图。咱们不能简单地使用视图函数——通用视图能够用许屡次——可是咱们能够用咱们给定的名字:

return HttpResponseRedirect(reverse('poll_results', args=(p.id,)))
运行开发服务器,用你基于通用视图的调查应用程序。

更多关于通用视图的视觉,请查看通用视图文档。

3、即未来临

这个教程眼下在这结束了。教程更多的安装将会涉及:

    表单高级处理;

    用RSS框架;

    用缓存框架;

    用评价框架;

    高级管理特征:权限;

    高级管理特征:定制JavaScript;

同时,你可能想查看一些点,从这里到哪里去。

教程4结束!

整个教程结束,明天开始Django-cms的官方文档!

相关文章
相关标签/搜索