django-haystack 是一个专门提供搜索功能的 django 第三方应用,它支持 Solr、Elasticsearch、Whoosh、Xapian 等多种搜索引擎,配合著名的中文自然语言处理库 jieba 分词,就可以为我们的博客提供一个效果不错的博客文章搜索系统。
实现步骤:
第一步:在项目环境下安装需要的包
pip install whoosh django-haystack jieba
直接一次性安装完成这三个包。
第二步:在项目的 settings.py 做一些简单的配置
1.
INSTALLED_APPS = [ ... 'django.contrib.staticfiles', 'haystack', ... ]
2.在settings.py 页面最后加入:
HAYSTACK_CONNECTIONS = { 'default': { 'ENGINE': 'apps.blog.whoosh_cn_backend.WhooshEngine', 'PATH': os.path.join(BASE_DIR, 'whoosh_index'), }, } HAYSTACK_SEARCH_RESULTS_PER_PAGE = 10 HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
说明:(因为我们的文章都在blog这个APP下,所以就给blog这个APP添加搜索)
HAYSTACK_CONNECTIONS
的 ENGINE
指定了 django haystack 使用的搜索引擎,这里我们使用apps. blog.whoosh_cn_backend.WhooshEngine,apps.blog是我的项目下apps包下的blog这个APP
。PATH
指定了索引文件需要存放的位置,我们设置为项目根目录 BASE_DIR
下的 whoosh_index 文件夹(在建立索引是会自动创建)。
HAYSTACK_SEARCH_RESULTS_PER_PAGE
指定如何对搜索结果分页,这里设置为每 10 项结果为一页。
HAYSTACK_SIGNAL_PROCESSOR
指定什么时候更新索引,这里我们使用 haystack.signals.RealtimeSignalProcessor
,作用是每当有文章更新时就更新索引。由于博客文章更新不会太频繁,因此实时更新没有问题。
第三步:在 blog 应用下建立一个 search_indexes.py 文件,写上如下代码:(因为我们的文章都在blog这个APP下,所以就给blog这个APP添加搜索)
from haystack import indexes from .models import Post class PostIndex(indexes.SearchIndex, indexes.Indexable): text = indexes.CharField(document=True, use_template=True) def get_model(self): return Post def index_queryset(self, using=None): return self.get_model().objects.all()
说明:
这是 django haystack 的规定。要相对某个 app 下的数据进行全文检索,就要在该 app 下创建一个 search_indexes.py 文件,然后创建一个 XXIndex 类(XX 为含有被检索数据的模型,如这里的 Post),并且继承 SearchIndex
和 Indexable
。
我们需要为指定的数据添加一个索引(目录),在这里是为 Post 创建一个索引,索引的实现细节是我们不需要关心的,我们只关心为哪些字段创建索引,如何指定。
每个索引里面必须有且只能有一个字段为 document=True
,这代表 django haystack 和搜索引擎将使用此字段的内容作为索引进行检索(primary field)。注意,如果使用一个字段设置了document=True
,则一般约定此字段名为text
,这是在 SearchIndex
类里面一贯的命名,以防止后台混乱,当然名字你也可以随便改,不过不建议改。
第四步:指定索引的字段 (templates/search/indexes/ 这三个是固定的)
存放索引字段的模板的路径为 templates/search/indexes/你的APP名字/你的模型名字_text.txt(例如 templates/search/indexes/blog/post_text.txt),其内容为:
去到templates/search/indexes/blog/post_text.txt 里写入:
{{object.title}} {{object.context}}
第五步:配置URL
1.在总路由里加入以下URL:
path('search/', include('haystack.urls')),
2.如果你前面有哪个路由也是使用了search/,请一定先去删除或改掉,避免冲突报错
第六步:修改一下搜索表单,让它提交数据到 django haystack 搜索视图对应的 URL:
1. action="{% url 'haystack_search' %}"
2.name="q"(必须q)
完整代码:
<form class="navbar-form navbar-left" method="get" action="{% url 'haystack_search' %}" > <div class="form-group"> <input type="text" class="form-control" placeholder="站内搜" name="q"> </div> <button type="submit" class="btn btn-default" style="top: 5%">搜一搜</button> </form>
第七步:创建搜索结果显示页面
因为haystack_search
视图函数会将搜索结果传递给模板 search/search.html,(默认固定)因此创建这个模板文件,对搜索结果进行渲染:
路径:templates/search/search.html
代码:
{% extends 'base1.html' %} {% load highlight %} {% block title %} 博文搜索结果页 {% endblock %} {% block main %} <div class="header-banner"> <div class="container"> <h1>搜索结果</h1> <p>本页面为<span class="hidden-xs">本博客</span>关于{{ fenlei.name }}的全部搜索结果</p> <p>huigege|2019</p> <form class="navbar-form navbar-collapse" method="get" action="{% url 'haystack_search' %}"> <div class="form-group"> <input type="text" class="form-control" placeholder="站内搜" name="q"> <input type="submit" class="btn btn-default" style="top:5%"> </div> </form> </div> </div> <div class="container"> {% if query %} {% for result in page.object_list %} <div class="media" style="overflow: hidden"> <hr> <div class="media-left media-middle"> <a href="#"> <img class="media-object" src="{{ MEDIA_URL }}{{ result.object.img }}" alt="..." style="width: 120px;height: 120px"> </a> </div> <div class="media-body"> <h4 class="media-heading"><a href="{% url 'blog:post_read' result.object.pk %}" style="color:#333">{% highlight result.object.title with query %}</a></h4> <p class="blog-post-meta">发布时间:{{ result.object.put_in_time|date:"Y-m-d"}} 作者:{{ result.object.author.username }} 点赞量:{{ result.object.vote|default_if_none:0 }}</p> <p >{% highlight result.object.context with query %}</p> {# <p >{{ result.object.context|striptags|truncatechars:300|safe }}</p>#} </div> </div><!-- /.blog-post --> {% empty %} <p>未搜索到任何有关文章</p> {% endfor %} {% else %} 请输入搜索关键词,例如 django {% endif %} {% if page.has_previous or page.has_next %} <div> {% if page.has_previous %} <a href="?q={{ query }}&page={{ page.previous_page_number }}">{% endif %}« 上一页 {% if page.has_previous %}</a>{% endif %} | {% if page.has_next %}<a href="?q={{ query }}&page={{ page.next_page_number }}">{% endif %}下一页 »{% if page.has_next %}</a>{% endif %} </div> {% endif %} </div> {% endblock %}
说明:加载{% load highlight %} 是为了高亮关键字,因为haystack_search只会返回一个page变量,我们要拿到内容,就需要遍历他,遍历的格式为
{% for result in page.object_list %}
显示当中的字段,要这样:
{{ result.object.img }} object不能少。
高亮的字段就长这样:
{% highlight result.object.title with query %} 中间不能再加入其它的过滤器了
在base.html里设置高亮字段的颜色,这里设成红色:
<head> <title>Black & White</title> ... <style> span.highlighted { color: red; } </style> ... </head>
分页:
{% if page.has_previous or page.has_next %}
<div> {% if page.has_previous %} <a href="?q={{ query }}&page={{ page.previous_page_number }}">{% endif %}« 上一页 {% if page.has_previous %}</a>{% endif %} | {% if page.has_next %}<a href="?q={{ query }}&page={{ page.next_page_number }}">{% endif %}下一页 »{% if page.has_next %}</a>{% endif %} </div>
{% endif %} </div>
高亮显示进一步说明:
注意到百度的搜索结果页面,含有用户搜索的关键词的地方都是被标红的,在 django haystack 中实现这个效果也非常简单,只需要使用 {% highlight %} 模板标签即可,其用法如下:
# 使用默认值 {% highlight result.summary with query %} # 这里我们为 {{ result.summary }} 里所有的 {{ query }} 指定了一个<div></div>标签,并且将class设置为highlight_me_please,这样就可以自己通过CSS为{{ query }}添加高亮效果了,怎么样,是不是很科学呢 {% highlight result.summary with query html_tag "div" css_class "highlight_me_please" %} # 可以 max_length 限制最终{{ result.summary }} 被高亮处理后的长度 {% highlight result.summary with query max_length 40 %}
在博客文章搜索页中我们对 title 和 body 做了高亮处理:{% highlight result.object.title with query %},{% highlight result.object.body with query %}。高亮处理的原理其实就是给文本中的关键字包上一个 span 标签并且为其添加 highlighted 样式(当然你也可以修改这个默认行为,具体参见上边给出的用法)。
第八步:将jieba设置成默认分词系统
在blog这个APP下(你需要搜索哪个APP下),新建一个whoosh_cn_backend.py
里面的代码如下:请直接下载就行,不需要改动什么,代码下载
第九步:
最后一步就是建立索引文件了,运行命令 python manage.py rebuild_index
就可以建立索引文件了。
来看看搜搜效果吧,效果还不错。
7
登陆后方可评论