Bob's Blog

Web开发、测试框架、自动化平台、APP开发、机器学习等

返回上页首页

Django通过haystack搜索文章



像现在的博客网站写了一些文章,有时需要搜索符合部分关键词的笔记,可以使用django-haystack来快速实现搜索。这个功能已经加了很久了,到现在才回过头来总结一下笔记。

按haystack的官网说明,它支持Solr, Elasticsearch, Whoosh, Xapian这些搜索引擎。对django来说,我选择纯python的Whoosh,不过由于Whoosh是自带英文分词,需要额外安装jieba来做中文分词。

配置

先安装这几个组件

pip install whoosh django-haystack jieba

接着在settings.py中添加haystack

INSTALLED_APPS = [
    ...
    'haystack',
    ...
 ]

# haystack
HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'blog.whoosh_cn_backend.WhooshEngine',
        'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
    },
}
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 5
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

 

指定model对象和建立视图模板

接下来需要告诉haystack对哪些数据建立索引。比如我想对博客文章索引,那么在blog这个app的目录下新建一个文件search_indexes.py并引入Post模型对象(这个要看自己的定义的名字)。

from .models import Post
from haystack import indexes


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()

在这里,我们对text这个字段用了use_template=True,代表着我们将用一个数据模板来帮助搜索引擎建立索引。

目前博客并非前后端分离,于是存在名为templates的目录,我们需要在templates这个文件夹下为搜索结果建立一个视图模板。

在templates下新建文件夹search/indexes/blog,并在里面新建一个文件post_text.txt,内容如下:

{{ object.title }}
{{ object.text }}

这就相当于会搜索文章标题和文章正文。

搜索出来的结果也需要定义如何展示,于是在templates/search下新建一个search.html,如下图。

代码样例如下。搜索页面还是由base页面扩展而来,我这里是加了共同的header和footer,以此保持同样的风格。

{% for post in page.object_list %}这里则是对搜索结果的循环并展示在页面上。

{% extends 'blog/base.html' %}

{% load highlight %}

{% block content %}
  <div class="container" style="margin-top: 40px;">
    <div class="row">
      <div class="col-lg-8 col-md-10 mx-auto">
      {% for post in page.object_list %}
        {% if post.object.visiable.name != 'private' or user.is_authenticated %}
        <div class="post-preview">
          <p class="post-meta">
              {{ post.object.created_date|date }} - 由{{post.object.author}} &ensp;&ensp;
              <span class='comment-count'>{{ post.object.comment_set.count }} 评论</span> &ensp;&ensp;
              <span class='view-count'>{{ post.object.views }} 阅读</span>
          </p>
          {% if post.object.visiable.name == 'private' %}
            <h3 class="post-title"><a href="{% url 'post_detail' post.object.id %}">[private] - {{ post.object.title }}</a></h3>
          {% else %}
            <h3><a href="{% url 'post_detail' post.object.id %}">{{ post.object.title }}</a></h3>
          {% endif %}
          <h6 class="post-subtitle">{% highlight post.object.text with query max_length 40 %}</h6>
          <div class="read-more" style="padding:0 0 20px 0;">
              <a href="{% url 'post_detail' post.object.id %}" class="btn btn-outline-primary">继续阅读</a>
          </div>
            {% if post.object.category %}
                <div class="category">
                  <img src="/media/icons/icons8-category-40px-1.png" width="20" height="20">
                  <span class="badge badge-success">{{ post.object.category.name }}</span>
                </div>
            {% endif %}
            {% if post.object.tag.all %}
                <div class="tag"><img src="/media/icons/icons8-tag-64px-1.png" width="20" height="20">
                {% for t in post.object.tag.all %}
                    <span class="badge badge-info">{{ t.name }}</span>
                {% endfor %}
                </div>
            {% endif %}
        </div>
        <hr>
        {% endif %}
      {% empty %}
        <h1>您搜索的条件没有数据</h1>
      {% endfor %}
      </div>
    </div>
  </div>
{% endblock %}

接着需要添加haystack的路由,在url.py中添加如下。

urlpatterns = [
    ...
    path('search/', include('haystack.urls')),
    ...
 ]

 

高亮搜索结果

当然,搜索也是可以高亮关键词,在上面的search.html中已经定义了{ % load highlight % }。不过还需要定义一下highlight的css属性,比如我在base.html中定义高亮为红色。

<style>
    span.highlighted {
        color: red;
    }
</style>

可以在这个链接下看看效果:https://www.byincd.com/bobjiang/search/?q=django

 

中文搜索

不过如果想要中文搜索,还需要修改jieba作为中文分词器,否则搜索结果会不太理想。

把haystack的whoosh_backend.py复制到blog这个app目录中,比如我用了virtualenv,路径类似于/venv/lib/python3.6/site-packages/haystack/backends/whoosh_backend.py,更名为whoosh_cn_backend.py。

并在该文件顶部引入jieba的ChineseAnalyzer。

from jieba.analyse import ChineseAnalyzer

163行也要换成ChineseAnalyzer。

#schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=StemmingAnalyzer(), field_boost=field_class.boost, sortable=True)  # 原先的注释掉
schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(), field_boost=field_class.boost, sortable=True)  # 新增的

整个过程就是:用户打开页面查看文章,haystack就会对标题和正文建立索引,然后当用户搜索时,haystack的视图函数会将搜索结果返回到search.html来渲染,最终呈现出来。当然也可以运行python manage.py rebuild_index来生成索引。

下一篇:  Django restframework加Vue打造前后端分离的网站(十)美化界面
上一篇:  Django restframework加Vue打造前后端分离的网站(九)查询筛选和搜索

共有0条评论

添加评论

暂无评论