在搭建博客的过程中, 随着博客的数量越来越多, 不可避免的用到搜索功能. 同时为了方便用户快速找到感兴趣的相关内容, 也需要添加一个站内搜索功能. django-haystack 是一个专门提供搜索功能的 django 第三方应用,它支持 Solr、Elasticsearch、Whoosh、Xapian 等多种搜索引擎,配合著名的中文自然语言处理库 jieba 分词,就可以为我们的博客提供一个效s果不错的博客文章搜索系统。

安装

  • Whoosh. 一个由Python实现的全文搜索引擎
  • jieba 中文分词
  • django-haystack
pip install whoosh django-haystack jieba

配置

首先是把 django haystack 加入到 INSTALLED_APPS 选项里:

INSTALLED_APPS = [
    'django.contrib.admin',
    # 其它 app...
    'haystack',
    'blog',
    'comments',
]

添加如下选项

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': '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'

这里的whoosh_cn_backend 需要在对应的app下面创建; HAYSTACK_SEARCH_RESULTS_PER_PAGE 指明每页的搜索结果数量; HAYSTACK_SIGNAL_PROCESSOR 指明更新文章的时机, 这里选择每当有新文章的时候更新索引, 由于博客不会频繁添加删除, 所以这种实时更新索引可以接受.

搜索文件建立

这里需要新建一个文件, search_indexes.py 用来说明应该使用哪些数据来建立索引. 针对博客来说, 需要建立索引的是blog这个应用下的Blog模型. 故相应的详情如下:

from haystack import indexes
from .models import Blog


class BlogIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)

    def get_model(self):
        return Blog

    def index_queryset(self, using=None):
        return self.get_model().objects.all()

注意:

  • 每个索引里面必须有且只能有一个字段为 document=True
  • use_template=True 允许我们使用数据模板去建立搜索引擎索引的文件. 数据模板的路径为 templates/search/indexes/youapp/\<model_name>_text.txt

这里创建博客的数据模板为:

templates/search/indexes/blog/blog_text.txt
{{ object.title }}
{{ object.content }}

这里说明使用title和content两个字段的内容对博客进行全文索引.

配置url

在项目的主url文件中添加如下url

path('search/', include('haystack.urls'))

配置whoosh_cn_backend

在blog下新建一个文件 whoosh_cn_backend.py, 将

schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=StemmingAnalyzer(), field_boost=field_class.boost, sortable=True)

将其中的analyzer修改为中文分词:

schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(), field_boost=field_class.boost, sortable=True)

添加搜索表单

这里选择在base.html 文件中添加一个搜索框, 这样所有的页面都能共享到这个搜索框了

<form action="{% url 'haystack_search' %}" class="navbar-form navbar-right" method="get">
    <input name="q" type="text" placeholder="搜索博文" class="form-control">
    <button type="submit">
        <span class="glyphicon glyphicon-search"></span>
    </button>
</form>

action为 {% url 'haystack_search' %} 指明了搜索使用的是haystack 的url.

获得搜索结果

haystack的搜索结果返回给 search/search.html, 需要先创建这个文件.

{% extends 'base.html' %}
{% load highlight %}
{% load comment_tags %}

{% block content %}
    <div class="container">
        <div class="row">
            <div class="col-sm-8 col-md-10 col-md-offset-1">
                <div class="panel panel-default">
                    <div class="panel-heading">{% block block_list_title %}博客列表{% endblock %}</div>
                    <div class="panel-body">
                        {% if query %}
                            {% for blog in page.object_list %}
                                <div class="blog">
                                    <h3>
                                        <a href="{% url 'blog_detail' blog.object.pk %}">
                                            {{ blog.object.title }}
                                        </a>
                                    </h3>

                                    <p class="blog-info">
                                        {% for tag in blog.object.tags.all %}
                                            <span class="glyphicon glyphicon-tag" aria-hidden="true"></span>
                                            <a href="{% url 'blogs_with_tag' tag.pk %}">
                                                {{ tag.name }}
                                            </a>
                                        {% endfor %}

                                        <span class="glyphicon glyphicon-time" aria-hidden="true"></span>{{ blog.object.created_time|date:"Y-m-d" }}&nbsp;&nbsp;
                                        阅读({{ blog.object.get_read_num }})&nbsp;&nbsp;
                                        评论({% get_comment_count blog.object %})
                                    </p>
                                </div>
                                <div class="entry-content clearfix">
                                    <p>{% highlight blog.object.content with query %}</p>
                                </div>
                            {% empty %}
                                <div class="blog">
                                    <h3>没有搜索到你想要的结果!</h3>
                                </div>
                            {% endfor %}
                            {% if page.has_previous or page.has_next %}
                                <div>
                                    {% if page.has_previous %}
                                        <a href="?q={{ query }}&amp;page={{ page.previous_page_number }}">{% endif %}&laquo; 上一页
                                    {% if page.has_previous %}</a>{% endif %}
                                    |
                                    {% if page.has_next %}<a href="?q={{ query }}&amp;page={{ page.next_page_number }}">{% endif %}下一页
                                    &raquo;{% if page.has_next %}</a>{% endif %}
                                </div>
                            {% endif %}
                        {% else %}
                            请输入搜索关键词,例如 django
                        {% endif %}
                    </div>
                </div>
            </div>
        </div>
    </div>

{% endblock %}

如果是搜索的内容, 还想要对搜索的原始文本进行高亮, 所以这里添加了如下代码

<div class="entry-content clearfix">
    <p>{% highlight blog.object.content with query %}</p>
</div>

完成

版权声明:本文为sksun原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/sksun/p/13087163.html