准备工作
逻辑
尽管细节不同,但是搜索和列表有很多类似的地方:它们都是先检索出一些文章对象,并将其展示给用户。上一章已经说过,代码重复是万恶之源,好的实践必须把功能类似的模块尽量复用起来。基于这个原则,我们打算继续在原有的article_list()上添砖加瓦,让其功能更加的强大。
随着项目越来越庞大,又需要将功能复杂的模块拆分成更简单的多个模块。目前我们还不用担心这个问题。
更酷的是,我们希望搜索出来的文章也能够按照时间、热度等各种方式进行排序。因此需要构造一个新的参数search,能够和之前的order参数进行联合查询。
GET还是POST?
用户搜索内容时提交的文本,可以用GET请求提交,也可以用POST请求提交。根据实际的需要进行选择。
因为order是用GET提交的,并且翻页是GET请求,因此选择GET方式提交搜索文本,可以方便地和之前的模块结合起来。
之前我们已经用过表单组件<form method="POST">,通过POST请求提交数据。表单组件同样也可以提交GET请求,只要去掉method="POST"属性就可以了。
Q对象
Model.objects.all()能够返回表中的所有对象。
对应的,Model.objects.filter(**kwargs)可以返回与给定参数匹配的部分对象。
还有Model.objects.exclude(**kwargs)返回与给定参数不匹配的对象
如果想对多个参数进行查询怎么办?比如同时查询文章标题和正文内容。这时候就需要Q对象。
视图
那么按照前面说好的,修改article_list():
重点知识如下:
新增参数search,存放需要搜索的文本。若search不为空,则检索特定文章对象。
留意filter中Q对象的用法。Q(title__icontains=search)意思是在模型的title字段查询,icontains是不区分大小写的包含,中间用两个下划线隔开。search是需要查询的文本。多个Q对象用管道符|隔开,就达到了联合查询的目的。
icontains不区分大小写,对应的contains区分大小写
为什么需要search = ''语句?如果用户没有搜索操作,则search = request.GET.get('search')会使得search = None,而这个值传递到模板中会错误地转换成"None"字符串!等同于用户在搜索“None”关键字,这明显是错误的。
完成本章内容后,可以删除此语句看看效果
除此之外还有一点小的代码优化工作:将需要重复用到order = request.GET.get('order')提取到顶部,让模块稍稍清爽一点。
模板
还是修改文章列表的模板文件。
需要修改的内容稍多,仔细一些不要看错:
面包屑组件、页码组件都改动了href:增加了search参数
新增搜索栏,以GET请求提交search参数;required属性阻止用户提交空白文本
新增搜索提示语。好的UI必须让用户了解当前的状态
Emmm...想想也不用改动其他东西了。
开始测试吧!
测试
还是打开文章列表页面:
出现了搜索栏!并且翻页、最热等功能一切正常。
在搜索栏中输入“PYTHON”,结果如下:
成功将标题或正文中含有"python"关键字的文章检索出来了,并且是忽略大小写的。点击最热可以让检索结果按浏览量排序,翻页功能也正常工作。很好,达成了目标!
学到这里的读者应该感到自豪:你用了同一个url,集成了很多种功能,展示了不同的内容!这对新手来说其实并不容易做到。
这种方法有一个小缺点:有的时候url中会包含像search=''(空值)这样无意义的字符串,强迫症简直不能忍。所幸这无伤大雅,通常用户并不会关心你的url是什么样子的,只要网页美观好用就行。
网友评论