第七章 表单处理.docx

上传人:b****6 文档编号:4946469 上传时间:2022-12-12 格式:DOCX 页数:15 大小:25.48KB
下载 相关 举报
第七章 表单处理.docx_第1页
第1页 / 共15页
第七章 表单处理.docx_第2页
第2页 / 共15页
第七章 表单处理.docx_第3页
第3页 / 共15页
第七章 表单处理.docx_第4页
第4页 / 共15页
第七章 表单处理.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

第七章 表单处理.docx

《第七章 表单处理.docx》由会员分享,可在线阅读,更多相关《第七章 表单处理.docx(15页珍藏版)》请在冰豆网上搜索。

第七章 表单处理.docx

第七章表单处理

TheDjangoBook

About|Commenthelp|Contactus|Errata|BuytheprintversiononA

已完成93段共有93段完成度100%|中英文对照|英文|中文|上一章|目录|下一章|翻译|

第七章表单处理

本章作者是SimonWillison

经过上一章,你应该对简单网站有个全面的认识。

这一章,来处理web开发的下一个难题:

建立用户输入的视图。

我们会从手工打造一个简单的搜索页面开始,看看怎样处理浏览器提交而来的数据。

然后我们开始使用Django的forms框架。

搜索

在web应用上,有两个关于搜索获得巨大成功的故事:

Google和Yahoo,通过搜索,他们建立了几十亿美元的业务。

几乎每个网站都有很大的比例访问量来自这两个搜索引擎。

甚至,一个网站是否成功取决于其站内搜索的质量。

因此,在我们这个网站添加搜索功能看起来好一些。

开始,在URLconf(mysite.urls)添加搜索视图。

添加类似(r'^search/$','mysite.books.views.search')设置URL模式。

下一步,在视图模块(mysite.books.views)中写这个search视图:

fromdjango.db.modelsimportQ

fromdjango.shortcutsimportrender_to_response

frommodelsimportBook

defsearch(request):

query=request.GET.get('q','')

ifquery:

qset=(

Q(title__icontains=query)|

Q(authors__first_name__icontains=query)|

Q(authors__last_name__icontains=query)

results=Book.objects.filter(qset).distinct()

else:

results=[]

returnrender_to_response("books/search.html",{

"results":

results,

"query":

query

})

这里有一些需要注意的,首先request.GET,这从Django中怎样访问GET数据;POST数据通过类似的request.POST对象访问。

这些对象行为与标准Python字典很像,在附录H中列出来其另外的特性。

什么是GETandPOST数据?

GET和POST是浏览器使用的两个方法,用于发送数据到服务器端。

一般来说,会在html表单里面看到:

它指示浏览器向/books/search/以GET的方法提交数据

关于GET和POST这两个方法之间有很大的不同,不过我们暂时不深入它,如果你想了解更多,可以访问:

http:

//www.w3.org/2001/tag/doc/whenToUseGet.html。

所以下面这行:

query=request.GET.get('q','')

寻找名为q的GET参数,而且如果参数没有提交,返回一个空的字符串。

注意在request.GET中使用了get()方法,这可能让大家不好理解。

这里的get()是每个python的的字典数据类型都有的方法。

使用的时候要小心:

假设request.GET包含一个'q'的key是不安全的,所以我们使用get('q','')提供一个缺省的返回值''(一个空字符串)。

如果只是使用request.GET['q']访问变量,在Get数据时q不可得,可能引发KeyError.

其次,关于Q,Q对象在这个例子里用于建立复杂的查询,搜索匹配查询的任何书籍.技术上Q对象包含QuerySet,可以在附录C中进一步阅读.

在这个查询中,icontains使用SQL的LIKE操作符,是大小写不敏感的。

既然搜索依靠多对多域来实现,就有可能对同一本书返回多次查询结果(例如:

一本书有两个作者都符合查询条件)。

因此添加.distinct()过滤查询结果,消除重复部分。

现在仍然没有这个搜索视图的模板,可以如下实现:

DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01//EN">

Search{%ifquery%}Results{%endif%}

Search

Search:

{%ifquery%}

Resultsfor"{{query|escape}}":

{%ifresults%}

    {%forbookinresults%}

  • {{book|escape}}

    {%endfor%}

{%else%}

Nobooksfound

{%endif%}

{%endif%}

希望你已经很清楚地明白这个实现。

不过,有几个细节需要指出:

表单的action是.,表示当前的URL。

这是一个标准的最佳惯常处理方式:

不使用独立的视图分别来显示表单页面和结果页面;而是使用单个视图页面来处理表单并显示搜索结果。

我们把返回的查询值重新插入到中去,以便于读者可以完善他们的搜索内容,而不必重新输入搜索内容。

在所有使用query和book的地方,我们通过escape过滤器来确保任何可能的恶意的搜索文字被过滤出去,以保证不被插入到页面里。

这对处理任何用户提交数据来说是必须的!

否则的话你就开放你的网站允许跨站点脚本(XSS)攻击。

在第十九章中将详细讨论了XSS和安全。

不过,我们不必担心数据库对可能有危害内容的查询的处理。

Django的数据库层在这方面已经做过安全处理。

【译注:

数据库层对查询数据自动Escape,所以不用担心】

现在我们已经作了搜索。

进一步要把搜索表单加到所有的页面(例如,在base模板);这个可以由你自己完成。

下面,我们看一下更复杂的例子。

事先我们讨论一个抽象的话题:

完美表单。

完美表单

表单经常引起站点用户的反感。

我们考虑一下一个假设的完美的表单的行为:

它应该问用户一些信息,显然,由于可用性的问题,使用HTML

所提交的数据应该多方面的验证。

Web应用安全的金科玉律是从不要相信进来的数据,所以验证是必需的。

如果用户有一些错误,表单应该重新显示详情,错误信息。

原来的数据应该已经填好,避免用户重新录入,

表单应该在所有域验证正确前一直重新显示。

建立这样的表单好像需要做很多工作!

幸好,Django的表单框架已经设计的可以为你做绝大部分的工作。

你只需要提供表单域的描述,验证规则和简单的模板即可。

这样就只需要一点的工作就可以做成一个完美的表单。

创建一个回馈表单

做好一个网站需要注意用户的反馈,很多站点好像忘记这个。

他们把联系信息放在FAQ后面,而且好像很难联系到实际的人。

一个百万用户级的网站,可能有些合理的策略。

如果建立一个面向用户的站点,需要鼓励回馈。

我们建立一个简单的回馈表单,用来展示Django的表单框架。

开始,在URLconf里添加(r'^contact/$','mysite.books.views.contact'),然后定义表单。

在Django中表单的创建类似MODEL:

使用Python类来声明。

这里是我们简单表单的类。

为了方便,把它写到新的forms.py文件中,这个文件在app目录下。

fromdjangoimportnewformsasforms

TOPIC_CHOICES=(

('general','Generalenquiry'),

('bug','Bugreport'),

('suggestion','Suggestion'),

classContactForm(forms.Form):

topic=forms.ChoiceField(choices=TOPIC_CHOICES)

message=forms.CharField()

sender=forms.EmailField(required=False)

NewForms是什么?

当Django最初推出的时候,有一个复杂而难用的form系统。

用它来构建表单简直就是噩梦,所以它在新版本里面被一个叫做newforms的系统取代了。

但是鉴于还有很多代码依赖于老的那个form系统,暂时Django还是同时保有两个forms包。

在本书写作期间,Django的老form系统还是在django.forms中,新的form系统位于django.newforms中。

这种状况迟早会改变,django.forms会指向新的form包。

但是为了让本书中的例子尽可能广泛地工作,所有的代码中仍然会使用django.newforms。

一个Django表单是django.newforms.Form的子类,就像Django模型是django.db.models.Model的子类一样。

在django.newforms模块中还包含很多Field类;Django的文档()中包含了一个可用的Field列表。

我们的ContactForm包含三个字段:

一个topic,它是一个三选一的选择框;一个message,它是一个文本域;还有一个sender,它是一个可选的email域(因为即使是匿名反馈也是有用的)。

还有很多字段类型可供选择,如果它们都不满足要求,你可以考虑自己写一个。

form对象自己知道如何做一些有用的事情。

它能校验数据集合,生成HTML“部件”,生成一集有用的错误信息,当然,如果你确实很懒,它也能绘出整个form。

现在让我们把它嵌入一个视图,看看怎么样使用它。

在views.py里面:

fromdjango.db.modelsimportQ

fromdjango.shortcutsimportrender_to_response

frommodelsimportBook

**fromformsimportContactForm**

defsearch(request):

query=request.GET.get('q','')

ifquery:

qset=(

Q(title__icontains=query)|

Q(authors__first_name__icontains=query)|

Q(authors__last_name__icontains=query)

results=Book.objects.filter(qset).distinct()

else:

results=[]

returnrender_to_response("books/search.html",{

"results":

results,

"query":

query

})

**defcontact(request):

**

**form=ContactForm()**

**returnrender_to_response('contact.html',{'form':

form})**

添加contact.html文件:

DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01//EN">

Contactus

Contactus

{{form.as_table}}

最有意思的一行是{{form.as_table}}。

form是ContactForm的一个实例,我们通过render_to_response方法把它传递给模板。

as_table是form的一个方法,它把form渲染成一系列的表格行(as_ul和as_p也是起着相似的作用)。

生成的HTML像这样:

Topic:

Generalenquiry

Bugreport

Suggestion

Message:

Sender:

请注意:

和标签并没有包含在内;我们需要在模板里定义它们,这给予我们更大的控制权去决定form提交时的行为。

Label元素是包含在内的,令访问性更佳(因为label的值会显示在页面上)。

我们的form现在使用了一个部件来显示message字段。

但我们不想限制我们的用户只能输入一行文本,所以我们用一个