第七章 表单处理Word文档下载推荐.docx

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

第七章 表单处理Word文档下载推荐.docx

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

第七章 表单处理Word文档下载推荐.docx

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表单里面看到:

<

formaction="

/books/search/"

method="

get"

>

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

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

http:

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

所以下面这行:

query=request.GET.get('

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

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

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

使用的时候要小心:

假设request.GET包含一个'

的key是不安全的,所以我们使用get('

)提供一个缺省的返回值'

(一个空字符串)。

如果只是使用request.GET['

]访问变量,在Get数据时q不可得,可能引发KeyError.

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

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

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

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

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

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

!

DOCTYPEHTMLPUBLIC"

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

htmllang="

en"

head>

<

title>

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

/title>

/head>

body>

h1>

Search<

/h1>

."

GET"

labelfor="

q"

Search:

/label>

inputtype="

text"

name="

value="

{{query|escape}}"

submit"

Search"

/form>

{%ifquery%}

h2>

Resultsfor"

/h2>

{%ifresults%}

ul>

{%forbookinresults%}

li>

{{book|escape}}<

/l1>

{%endfor%}

/ul>

{%else%}

p>

Nobooksfound<

/p>

{%endif%}

/body>

/html>

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

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

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

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

不使用独立的视图分别来显示表单页面和结果页面;

而是使用单个视图页面来处理表单并显示搜索结果。

我们把返回的查询值重新插入到<

input>

中去,以便于读者可以完善他们的搜索内容,而不必重新输入搜索内容。

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

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

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

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

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

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

【译注:

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

现在我们已经作了搜索。

进一步要把搜索表单加到所有的页面(例如,在base模板);

这个可以由你自己完成。

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

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

完美表单。

完美表单

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

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

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

label>

元素和有用的上下文帮助是很重要的。

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

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里面:

**fromformsimportContactForm**

**defcontact(request):

**

**form=ContactForm()**

**returnrender_to_response('

contact.html'

{'

form'

form})**

添加contact.html文件:

Contactus<

POST"

table>

{{form.as_table}}

/table>

Submit"

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

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

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

生成的HTML像这样:

tr>

th>

id_topic"

Topic:

/th>

td>

selectname="

topic"

id="

optionvalue="

general"

Generalenquiry<

/option>

bug"

Bugreport<

suggestion"

Suggestion<

/select>

/td>

/tr>

id_message"

Message:

message"

/>

id_sender"

Sender:

sender"

请注意:

和<

form>

标签并没有包含在内;

我们需要在模板里定义它们,这给予我们更大的控制权去决定form提交时的行为。

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

我们的form现在使用了一个<

inputtype=”text”>

部件来显示message字段。

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

textarea>

部件来替代:

message=forms.CharField(**widget=forms.Textarea()**)

forms框架把每一个字段的显示逻辑分离到一组部件(widget)中。

每一个字段类型都拥有一个默认的部件,我们也可以容易地替换掉默认的部件,或者提供一个自定义的部件。

现在,提交这个form没有在后台做任何事情。

让我们把我们的校验规则加进去:

defcontact(request):

ifrequest.method=='

POST'

form=ContactForm(request.POST)

form=ContactForm()

returnrender_to_response('

form})

一个form实例可能处在两种状态:

绑定或者未绑定。

一个绑定的实例是由字典(或者类似于字典的对象)构造而来的,它同样也知道如何验证和重新显示它的数据。

一个未绑定的form是没有与之联系的数据,仅仅知道如何显示其自身。

现在可以试着提交一下这个空白的form了。

页面将会被重新显示出来,显示一个验证错误,提示我们message字段是必须的。

现在输入一个不合法的email地址,EmailField知道如何验证email地址,大多数情况下这种验证是合理的。

设置初始数据

向form的构造器函数直接传递数据会把这些数据绑定到form,指示form进行验证。

我们有时也需要在初始化的时候预先填充一些字段——比方说一个编辑form。

我们可以传入一些初始的关键字参数:

form=CommentForm(initial={'

sender'

'

user@'

})

如果我们的form总是会使用相同的默认值,我们可以在form自身的定义中设置它们

message=forms.CharField(widget=forms.Textarea(),

**initial="

Replacewithyourfeedback"

**)

处理提交

当用户填完form,完成了校验,我们需要做一些有用的事情了。

在本例中,我们需要构造并发送一个包含了用户反馈的email,我们将会使用Django的email包来完成

首先,我们需要知道用户数据是不是真的合法,如果是这样,我们就要访问已经验证过的数据。

forms框架甚至做的更多,它会把它们转换成对应的Python类型。

我们的联系方式form仅仅处理字符串,但是如果我们使用IntegerField或者DataTimeField,forms框架会保证我们从中取得类型正确的值。

测试一个form是否已经绑定到合法的数据,使用is_valid()方法:

form=ContactForm(request.POST)

ifform.is_valid():

#Processformdata

现在我们要访问数据了。

我们可以从request.POST里面直接把它们取出来,但是这样做我们就丧失了由framework为我们自动做类型转换的好处了。

所以我们要使用form.clean_data:

topic=form.clean_data['

topic'

]

message=form.clean_data['

message'

sender=form.clean_data.get('

noreply@'

#...

请注意因为sender不是必需的,我们为它提供了一个默认值。

终于,我们要记录下用户的反馈了,最简单的方法就是把它发送给站点管理员,我们可以使用send_mail方法:

fromdjango.core.mailimportsend_mail

#...

send_mail(

Feedbackfromyoursite,topic:

%s'

%topic,

message,sender,

['

administrator@'

send_mail方法有四个必须的参数:

主题,邮件正文,from和一个接受者列表。

send_mail是Django的EmailMessage类的一个方便的包装,EmailMessage类提供了更高级的方法,比如附件,多部分邮件,以及对于邮件头部的完整控制。

发送完邮件之后,我们会把用户重定向到确认的页面。

完成之后的视图方法如下:

发送完邮件之后,我们会把用户重定向到确认的页面。

fromdjango.httpimportHttpResponseRedirect

fromformsimportContactForm

ifform.is_valid():

send_mail(

returnHttpResponseRedirect('

/contact/thanks/'

在POST之后立即重定向

在一个POST请求过后,如果用户选择刷新页面,这个请求就重复提交了。

这常常会导致我们不希望的行为,比如重复的数据库记录。

在POST之后重定向页面是一个有用的模式,可以避免这样的情况出现:

在一个POST请求成功的处理之后,把用户导引到另外一个页面上去,而不是直接返回HTML页面。

自定义校验规则

假设我们已经发布了反馈页面了,email已经开始源源不断地涌入了。

只有一个问题:

一些email只有寥寥数语,很难从中得到什么详细有用的信息。

所以我们决定增加一条新的校验:

来点专业精神,最起码写四个字,拜托。

我们有很多的方法把我们的自定义校验挂在Django的form上。

如果我们的规则会被一次又一次的使用,我们可以创建一个自定义的字段类型。

大多数的自定义校验都是一次性的,可以直接绑定到form类.

我们希望message字段有一个额外的校验,我们增加一个clean_message方法:

message=forms.CharField(widget=forms.Textarea())

defclean_message(self):

message=self.clean_data.get('

num_words=len(

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 军事

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1