45、站内简单搜索
1、搜索功能作用
- 1、让更多博客内容被挖掘出来
- 2、用户体验更好
2、搜索功能实现方法
- 1、用户提交搜索请求(参数搜索关键字)
- 2、根据关键字查找博客标题和内容(通过
filter
筛选方式)
我们先要实现在页面加一个搜索框,加在导航栏的右侧,那这就要加到最底层的模板,
查看Bootstrap,在“组件”——“导航条”,
修改base.html如下:
刷新页面
这个submit按钮有点多余,我们可以改个样式,查看Bootstrap组件 图标
修改base.html如下:
刷新页面:
然后修改一下样式,让搜索的图标放到搜索框里面来,修改base.css如下:
刷新页面:
接着我们回到base.html这里,我们点击提交按钮,会把表单这些东西给提交上去,也就是input标签里面的内容。这里我们设置提交参数名称name为wd,这样提交的内容就会提交给后端,那么后端得有一个处理方法给这个form去提交,所以我们需要给后端加一个处理链接和方法。
首先我们给后端加一个处理方法,这个是全局的,所以我们在mysite/views.py中进行添加:
然后配置路由,在mysite/urls.py中:
这样,有了处理方法和路由之后,我们就有了对应的处理方法可以处理前端页面提交的这个请求。那么现在我们给这个请求指定一个路径让它提交,用action参数来指定,修改base.html如下:
接着我们回到处理方法mysite/views.py对search方法进行编写:
def search(request):
search_word = request.GET.get('wd', '') # 获取到wd这个参数
search_blogs = Blog.objects.filter(title__icontains=search_word) # = 全部匹配;__contains= 部分匹配,区分大小写;__icontains= 忽略大小写
context = {}
context['search_word'] = search_word
context['search_blogs'] = search_blogs
return render(request, 'search.html', context) # 通过render渲染出来,具体渲染页面为search.html,传递的参数是个字典context
接着我们创建下模板页面search.html,这是全局的,我们放到templates目录下:
<!-- C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\templates\search.html -->
{% extends 'base.html' %}
{% block title %}
我的网站 | 搜索
{% endblock %}
{% block header_extends %}
{% endblock %}
{% block nav_home_active %}active{% endblock %}
{% block content %}
{{ search_word }}
{% for blog in search_blogs %}
{{ blog.title }}
{% empty %}
<p>搜索不到任何内容</p>
{% endfor %}
{% endblock %}
刷新页面,搜索“内容”“for”
这样,我们搜索的核心基本功能已经实现了,接下来我们完善html页面
3、搜索规则
- 1、部分匹配(只要标题或内容存在搜索内容即可)
- 2、多个关键字可以用空格隔开(Q方法实现复杂逻辑)
- 3、搜索结果分页(下一页和上一页)
- 对TextField长文本字段进行部分匹配相对比较慢,建议不对TextField长文本字段搜索
先修改views.py如下:
修改search.html如下:
<!-- C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\templates\search.html -->
{% extends 'base.html' %}
{% block title %}
我的网站 | 搜索
{% endblock %}
{% block header_extends %}
{% endblock %}
{% block nav_home_active %}active{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% if search_word == '' %}
<h3>你没有搜索任何内容。</h3>
<p>你可以尝试输入点什么东西,例如:Django</p>
{% else %}
<h3>搜索“{{ search_word }}”,找到{{ search_blogs_count }}个结果</h3>
<hr>
{% for blog in search_blogs %}
<a href="{% url 'blog_detail' blog.pk %}">
<h4>{{ blog.title }}</h4>
</a>
<p>{{ blog.content | striptags | truncatechars_html:100 }}</p>
{% empty %}
<p>没有找到任何东西,换个关键词试试吧</p>
{% endfor %}
{% endif %}
</div>
</div>
</div>
{% endblock %}
刷新页面
我们可以看到如果搜索到的内容比较多的话,显示出来就比较长,我们可以做一个简单的分页(参考blog里面的views.py里面的分页代码)修改views.py如下:
修改search.html如下:
刷新页面
这样,我们就实现了分页功能。现在我们拓展下搜索规则,
以空格分开的搜索关键词是并列的关系,用filter不能直接实现筛选并列关键词,如果用逗号写多个筛选条件,逗号是and逻辑,表示同时满足,而我们空格分隔关键词想要的是or逻辑关系,这里django有实现的方法,查看官方文档:
修改views.py如下(对应的将search.html里面面所有的search_word全部替换成search_words)
# 搜索框对应的处理方法
def search(request):
search_words = request.GET.get('wd', '').strip() # 获取到wd这个参数
# 分词:按空格 & | ~
condition = None
for word in search_words.split(' '):
if condition is None:
condition = Q(title__icontains=word)
else:
condition = condition | Q(title__icontains=word)
search_blogs = []
if condition is not None:
# 筛选:搜索
# search_blogs = Blog.objects.filter(title__icontains=search_words) # = 全部匹配;__contains= 部分匹配,区分大小写;__icontains= 忽略大小写
search_blogs = Blog.objects.filter(condition)
# 分页
paginator = Paginator(search_blogs, 20) # 每多少项作为一页
page_num = request.GET.get('page', 1) # 获取页码参数(GET请求)。# 看有没有‘page’这个属性,如果没有,则默认给1
page_of_blogs = paginator.get_page(page_num)
context = {}
context['search_words'] = search_words
context['search_blogs_count'] = search_blogs.count()
# context['search_blogs'] = search_blogs
context['page_of_blogs'] = page_of_blogs
return render(request, 'search.html', context) # 通过render渲染出来,具体渲染页面为search.html,传递的参数是个字典context
templates/search.html:
<!-- C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\templates\search.html -->
{% extends 'base.html' %}
{% block title %}
我的网站 | 搜索
{% endblock %}
{% block header_extends %}
{% endblock %}
{% block nav_home_active %}active{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% if search_words == '' %}
<h3>你没有搜索任何内容。</h3>
<p>你可以尝试输入点什么东西,例如:Django</p>
{% else %}
<h3>搜索“{{ search_words }}”,找到{{ search_blogs_count }}个结果</h3>
<hr>
{% for blog in page_of_blogs %}
<a href="{% url 'blog_detail' blog.pk %}">
<h4>{{ blog.title }}</h4>
</a>
<p>{{ blog.content | striptags | truncatechars_html:100 }}</p>
{% empty %}
<p>没有找到任何东西,换个关键词试试吧</p>
{% endfor %}
{% endif %}
</div>
</div>
<!-- 上一页 下一页 -->
<div class="row" style="display: flex; justify-content: center;">
{% if page_of_blogs.has_previous %}
<a class="btn btn-default" href="{% url 'search' %}?wd={{ search_words }}&page={{page_of_blogs.previous_page_number}}">
上一页
</a>
{% endif %}
{% if page_of_blogs.has_next %}
<a class="btn btn-default" href="{% url 'search' %}?wd={{ search_words }}&page={{page_of_blogs.next_page_number}}">
下一页
</a>
{% endif %}
</div>
</div>
{% endblock %}
刷新页面,搜索“2 内容”,可以看到,成功搜索到标题包含“2”或“内容”的所有博客
至此,搜索关键字功能已经比较好的实现了
【遇到的小问题】:启动服务时显示出错“MySQLdb._exceptions.OperationalError: (2002, “Can’t connect to MySQL server on ‘localhost’ (10061)”)”
原因:MySQL连接断开了
解决办法:以管理员身份重新开一个cmd窗口,输入net start mysql
启动mysql