第七章 表单处理Word文档下载推荐.docx
- 文档编号:17899831
- 上传时间:2022-12-12
- 格式:DOCX
- 页数:15
- 大小:25.48KB
第七章 表单处理Word文档下载推荐.docx
《第七章 表单处理Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《第七章 表单处理Word文档下载推荐.docx(15页珍藏版)》请在冰豆网上搜索。
)
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(
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第七章 表单处理 第七 表单 处理