`

Django新手指南(7)

阅读更多

编写你的第一个Django程序,第四部分

 

本文继续第三部分讨论的内容。我们会继续开发网络投票程序并将深入研究简单的表单处理和缩减代码。

 

编写一个简单的表单

 

现在把上一部分中提到的polls/detail.html做一下修改,在模板代码中加入<form>标签:

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

 

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

 

<form action="/polls/{{ poll.id }}/vote/" method="post">

{% 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>

 

总结一下:

上面的模板会给每个投票的答案选项设置一个单选框。每个单选框的值对应Choice对象的ID字段;名称对应Choice对象的choice字段。这就是说,当有人勾选了单选框并提交时,浏览器会提交POST数据choice=3。这就是HTML的基本法则。

 

现在创建个Django视图来处理提交的数据。在第三部分中,我们的URLconf设置有下面的内容:

(r'^(?P<poll_id>\d+)/vote/$', 'vote'),

 

现在我们在mysite/polls/views.py中创建vote()视图:

from django.shortcuts import get_object_or_404, render_to_response

from django.http import HttpResponseRedirect

from django.core.urlresolvers import reverse

from mysite.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.",

        })

    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('mysite.polls.views.results', args=(p.id,)))

 

这段代码有些内容我们目前还没有提及到:

 

request.POST是一个类似于字典的对象,你可以用名称索引来引用提交的数据。这种情况下,request.POST['choice']会以字符串的形式返回被选中的投票选项的IDrequest.POST的值永远都是字符串。

同样在Django里,也可以用同样的方法从request.GET中获取GET数据。但是在这里我们使用request.POST,是因为为了保证数据是从POST方法提交过来的。

 

如果choicePOST数据中不存在,调用request.POST['choice']就会引发KeyError异常。上面的代码会检查是否触发KeyError异常,如果有异常就会重新显示提交表单和一段报错信息。

 

在增加了投票选项的统计数之后,最后返回了HttpResponseRedirect对象而不是HttpResponse对象。HttpResponseRedirect对象接收一个参数:跳转URL。(下面会说明怎么样构建URL

上面的注释里说明,你应该在POST数据处理完成之后永远返回HttpResponseRedirect对象。这个技巧不仅仅适用于Django,任何Web开发上都应该这么做。

 

在这个例子中我们在构造HttpResponseRedirect对象时使用了reverse()函数。这个函数可以解决硬编码URL产生的问题。我们只要传入要跳转的视图的名称和视图函数的参数就可以了。比如根据第三部分的URLconf设置,reverse()函数会返回下面的字符串:

'/polls/3/results/'

这里的3就是p.id的值。跳转后的URL会调用results视图函数并显示最终的页面。在这里你要使用视图函数的全名(包括前缀)。

 

在第三部分中提到,request是一个HttpRequest对象。要了解HttpRequest的更多内容,请参考文档request and response documentation

 

有人提交投票之后,vote()视图会跳转到对应的结果页面。现在来编写对应的视图:

def results(request, poll_id):

    p = get_object_or_404(Poll, pk=poll_id)

    return render_to_response('polls/results.html', {'poll': p})

 

这跟第三部分中的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>

 

现在访问/polls/1/并完成投票,你就能看到结果页面了,而且每次投票后都能看到数据有更新。如果没有勾选任何选项的话,你会看到错误信息。

 

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

 

detail()results()都太简单了,而且代码上也有重复。显示投票列表的index()也有类似的问题。

 

这些视图都代表了Web开发中的一类现象:根据URL中的参数从数据库中获取数据,加载模板并返回渲染后的内容。这类现象非常普遍,因此Django提供了快捷方法,称为“通用视图”。

 

有了通用视图,你就不需要写任何Python代码来编写程序了。

 

现在用通用视图来修改投票程序,我们就可以删除掉一些代码了。下面只需要做几步就能完成修改。

 

为什么要梳理代码?

一般,编写Django程序时,你需要估计一下使用通用视图是否适合你的系统,如果适合,那从最开始就应该使用通用视图而不是开发了一半程序再来改代码。但是本文有意从一开始就介绍自行编写视图的方法,是为了让读者理解核心内容。

就好像你要使用计算机,至少应该知道基本的数学知识。

 

首先,打开polls/urls.py。这里面的URLconf如下所示:

from django.conf.urls.defaults import *

 

urlpatterns = patterns('mysite.polls.views',

    (r'^$', 'index'),

    (r'^(?P<poll_id>\d+)/$', 'detail'),

    (r'^(?P<poll_id>\d+)/results/$', 'results'),

    (r'^(?P<poll_id>\d+)/vote/$', 'vote'),

)

 

将代码改成下面的样子:

from django.conf.urls.defaults import *

from mysite.polls.models import Poll

 

info_dict = {

    'queryset': Poll.objects.all(),

}

 

urlpatterns = patterns('',

    (r'^$', 'django.views.generic.list_detail.object_list', info_dict),

    (r'^(?P<object_id>\d+)/$', 'django.views.generic.list_detail.object_detail', info_dict),

    url(r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='polls/results.html'), 'poll_results'),

    (r'^(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),

)

 

我们这里用了两个通用视图:object_list()object_detail()。这两个视图分别用于“展示纪录的列表”和“展示某个特定的记录”。

l         每个通用视图都要知道需要使用哪些数据。这些数据在一个字典里提供。字典中的queryset索引对应的数据就是视图中要操作的对象。

l         object_detail()通用视图需要一个从URL中捕获的ID值,名称限定为object_id。所以我们把poll_id改成了object_id

l         results视图里我们加上了一个poll_results参数,这样就能在后面引用它的URL了(请看naming URL patterns文档)。这里还要使用django.conf.urls.defaultsurl()函数。在刚才这样的情景下使用url()函数是个很好的习惯。

 

一般,object_detail()通用视图使用<app name>/<model name>_detail.html作为模板。这里,该视图会使用polls/poll_detail.html。所以,把polls/detail.html更名为polls/poll_detail.html,然后在vote()中修改render_to_response()这一行。

 

同样,object_list()通用视图使用<app name>/<model name>_list.html作为模板。所以,把polls/index.html更名为polls/poll_list.html

 

由于在这个投票程序中的URLconf设置里,有多个纪录都用到了object_detail()视图,我们要人工给results视图指定模板名:template_name='polls/results.html'。否则,这些使用了同一个通用视图的URL就会加载同一个模板。注意这里我们用dict()来返回一个新的字典。

 

注意

django.db.models.QuerySet.all()是一个懒惰查询方法。

detail视图中只需要使用一条Poll纪录,而在这里使用Poll.objects.all()方法看起来让人觉得会影响性能。请别担心,Poll.objects.all()返回一个称为QuerySet的对象,实际上,这个对象只有在真正必要的时候才会去访问数据库。在查询数据库时,object_detail()视图会将范围缩减到单个纪录,所以只会从数据库返回被选中的纪录。

如果你想知道这其中到底是怎么工作的,Django 数据库API文档会告诉你QuerySet对象的懒惰特性

 

在前面几部分中,模板内都传入了一个包含polllatest_poll_listcontext对象。但是通用视图提供objectobject_list作为context对象。所以,需要修改模板文件来适应新的context变量。在你的模板中,将所有latest_poll_list替换为object_list,所有poll替换为object

 

你现在可以从polls/views.py中删除index()detail()result()视图了。我们不再需要这些代码了——它们已经被通用函数代替。

 

vote()视图还是必要的,但是还是要修改一下变量名。在调用render_to_response()时,将poll重命名为object

 

最后一件要做的事就是为了跳转到通用视图而修改一下URL的处理。在vote视图中,使用了reverse()来解决硬编码URL的问题。现在我们使用了通用视图,需要修改reverse()重新指向到通用视图。在reverse()中我们不能简单地再直接用视图的名称了——因为在URLconf中通用视图是可以多次使用的,这样就没办法分辨到底跳转到哪个URL——但是我们可以使用给定的名称:

return HttpResponseRedirect(reverse('poll_results', args=(p.id,)))

 

重新启动测试服务器,看看这个使用了通用视图的全新程序。

 

要了解更多通用视图的内容,请参考通用视图文档

分享到:
评论

相关推荐

    Django Web开发指南

    ### Django Web 开发指南 #### 一、简介 《Django Web 开发指南》是一本专为希望使用Python进行Web应用开发的技术人员所撰写的书籍。本书由Jeff Forcier、Paul Bissex与Wesley Chun共同编写,三位作者都是在Python...

    (简体中文) Python新手使用Django架站的16堂课

    D1二部分-D14~7堂是Django架构深入剖析 详细分析Django的MVC/MTV架构;D1三部分-D18~11堂为实用网站开发技巧;D1四部分-靠前2~16堂为实用网站开发教学 从设计、规划到实践 逐步指导读者在自己的主机环境下构建出有趣...

    Django中文版 教程.

    标题中提到的是“Django中文版 教程...综上所述,这份教程是全面介绍Django框架的中文版教材,不仅覆盖了Django的基本概念和操作,还深入探讨了高级主题和最佳实践,适合作为Python Web开发新手的入门指南和进阶参考。

    Django+Web开发指南

    ### Django+Web开发指南 #### 一、简介与概述 《Django+Web开发指南》是一本关于Python Web框架Django的详细介绍书籍...无论你是刚接触Django的新手还是已经有一定经验的开发者,都可以从中获得有价值的信息和指导。

    django1.5 开发文档

    - **5.1 至 5.2 常见问题解答**:提供了关于 Django 使用过程中可能遇到的常见问题及解答,有助于新手快速解决问题。 通过以上概览,我们可以看出 Django 1.5 文档覆盖了从入门到进阶的所有知识点,并且提供了丰富...

    新手使用Django架站的

    **Django新手指南** Django是一个基于Python的高级Web框架,它强调了代码的简洁性和可重用性,使得开发者可以快速地构建高效、可扩展的Web应用。本指南将帮助初学者理解Django的基本概念,并逐步学习如何使用Django...

    django1.8官方文档

    - **起步指南**:这部分是新手入门必备的教程,指导用户从零开始安装和配置 Django,并通过一个简单的示例应用程序来了解 Django 的基本结构和功能。 - **模型层**:解释了如何定义数据模型以及 Django ORM(对象...

    Django Documents

    本文档为 Django 1.5.3 版本提供了详尽的指导,旨在帮助开发者从零开始构建高质量的 Web 应用程序。文档由 Django 软件基金会发布于 2013 年 9 月 14 日。 #### 二、文档结构与主要内容 ##### 1. Django 文档概述 ...

    Django1.9 官方文档

    1.9版本的Django官方文档提供了从零开始学习Django的“First steps”部分,这部分内容是为新手或者刚开始学习编程的开发者准备的,内容包括从Django的基础概览、安装到具体的教程,涵盖了请求和响应、模型和管理后台...

    django document

    这部分通常会指导新手开发者如何设置开发环境,创建项目和应用,并编写简单的视图、模板和表单。 3. 模型和数据库 这部分会介绍如何定义数据模型,以及如何与数据库交互。Django提供了对象关系映射(ORM)系统,使得...

    Django web开发指南

    **Django Web开发指南** Django,一个基于Python的开源Web框架,因其高效、安全且易于使用的特点,已经成为全球开发者构建Web应用...无论你是Python新手还是资深开发者,这份指南都能成为你探索Django世界的宝贵资源。

    Django后端新手如何初始化配置

    ### Django后端新手如何初始化配置 对于初学者来说,Django 是一个功能强大且易于上手的 Python Web 开发框架。本文将详细指导你完成 Django 项目的初始化配置,并重点介绍如何连接数据库以及如何实现基本的增删改...

    django1.11 doc html版

    **Django 1.11 文档 HTML 版** Django 1.11 是一个功能强大、高效...无论你是正在学习Django的新手,还是寻求特定问题解决方案的开发者,都能从中受益。记得时常查阅文档,它会成为你Django开发旅程中不可或缺的伙伴。

    Django2.1完整手册-英文版

    这部分内容通常会引导新手快速上手Django框架。它从Django的概览开始,提供了一个快速安装指南。接下来会手把手地指导用户编写第一个Django应用程序,通常包含多个部分(例如七个部分),帮助用户逐步构建起一个完整...

    Django框架学习指南

    ### Django框架学习指南 #### 一、概述与背景 Django 是一个高级的 Python Web 框架,它鼓励快速开发、干净且实用的设计。它遵循 MVC(模型-视图-控制器)架构模式,旨在通过减少重复代码来简化Web应用程序的开发...

    Django官方文档.pdf

    首先,文档的标题“Django官方文档”表明了这是关于Django这一Python Web框架的权威指南。Django是一个高层次的Python Web框架,它促进了快速开发,并遵循MVC(模型-视图-控制器)设计模式。 接下来,文档的描述...

    django1.11.1

    这部分内容为新手提供了快速上手指南,包括如何安装 Django、创建项目、编写第一个应用等基础知识。 **4. 模型层 (The model layer)** 模型层是 Django 框架的核心之一,负责数据的存储和检索。这一章节详细介绍了...

    Django2.0.1官方文档

    - 新手可以通过官方文档中的“编写你的第一个Django应用”系列指南快速上手,这部分内容通常会引导初学者一步步完成从安装Django到创建、运行并测试一个基础Web应用的整个过程。 3. 模型层(The model layer) - ...

    Python新手使用Django架站的16堂课的范例 随书光盘

    本书分4部分,以16堂课来介绍Python新手使用Django架站的要点。第一部分(第1~3堂)以一个小型的个人博客网站为主轴,介绍如何快速建立一个实用的Django网站;第二部分(第4~7堂)是Django架构深入剖析,详细分析...

    django-chinese-docs pdf

    - **新手入门**:为初次接触Django的用户提供入门指南,包括环境搭建、项目创建等基础知识。 - **从零开始**:适合完全没有经验的新手,详细介绍如何一步步构建一个Django应用。 - **概览**:对Django的整体架构进行...

Global site tag (gtag.js) - Google Analytics