Django实现全文搜索
0.依赖安装
这里使用 django-haystack 来实现全文搜索的能力,django-haystack 是 Django 的全文搜索框架,能够将搜索引擎(如 Whoosh、Elasticsearch、Solr)集成到 Django 项目中,提供统一的搜索 API,支持多种后端搜索引擎。
pip install django-haystack whoosh安装如上依赖后,需要在 settings.py 中配置如下参数:
INSTALLED_APPS = [
# ...
'haystack',
]
# 配置 Haystack 使用 Whoosh 作为搜索后端
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
'PATH': os.path.join(BASE_DIR, 'whoosh_index'), # 索引存储路径
},
}
# 实时信号处理器 —— 每次模型变化自动更新索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'1.创建索引类
在需要索引的应用下方,创建名为 search_indexes.py文件,这个名称不能够修改。
例如要进行检索的模型对象如下:
class ArticlePost(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=100, unique=True)
content = models.TextField()
created = models.DateTimeField(default=timezone.now)
updated = models.DateTimeField(auto_now=True)
is_deleted = models.BooleanField(default=False)则创建的索引类如下所示:
from haystack import indexes
from article.models import ArticlePost
class ArticleIndex(indexes.SearchIndex, indexes.Indexable):
# text是提供搜索的字段
text = indexes.CharField(document=True, use_template=True)
# 这里要索引的字段依照需求添加,不用全部添加
author = indexes.CharField(model_attr='author')
title = indexes.CharField(model_attr='title')
content = indexes.CharField(model_attr='body')
uuid = indexes.CharField(model_attr='uuid')
created = indexes.DateTimeField(model_attr='created')
def get_model(self):
return ArticlePost
def index_queryset(self, using=None):
return self.get_model().objects.all()2.全文搜索主字段模板
创建如下模版文件:
templates/search/indexes/[app名称]/[索引的原始对象名称]_text.txt
# 放到这里就是
templates/search/indexes/article/articlepost_text.txt模板的内容如下,用于合并多个字段到 text 字段(全文搜索主字段)
{{ object.title }}
{{ object.content }}3.生成索引字段
python manage.py rebuild_index如果更新了数据或模型字段,可以重新运行这个命令。

4.创建搜索路由和模板文件
在 urls.py 中添加搜索视图的路由,如下所示
from django.urls import path, include
urlpatterns = [
# ...
path('search/', include('haystack.urls')), # 会自动生成 /search/?q=xxx 的搜索页面
]编写搜索视图的模板文件 templates/search/search.html,这里也可以直接使用,但是原始的搜索视图通常不可用,这里自定义编写搜索视图的模板页面:
<!-- extends表明此页面继承自 base.html 文件 -->
{% extends "base.html" %}
{% load static %}
{% load article_extras %}
<!-- 写入 base.html 中定义的 title -->
{% block title %}
搜索 | {{SITE_NAME}}
{% endblock title %}
<!-- 写入 base.html 中定义的 content -->
{% block content %}
<!-- 定义放置文章标题的div容器 -->
<div class="container search-container">
<div class="card mt-5 col-8">
<div class="card-line">
<strong class="mt-3 ms-3 left">检索字段:{{query}}</strong>
<p class="mt-3 me-3 right">共 {{ page.object_list|length }} 条结果</p>
</div>
<div class="border-bottom border-1 my-2"></div>
<div class="mt-2 ms-3 mb-2">站内搜索是对网站全文内容进行检索,将整个网站的文章的标题和内容进行分词存储,然后给每个分词建立索引,搜索功能返回的是全站文章中标题或者内容中包含关键词的文章。</div>
</div>
<div class="mt-3 col-8">
{% for article in page.object_list %}
<div class="card search-card card-shadow list-group-item mt-3">
<a href="/article/detail/{{ article.uuid }}/" class="text-decoration-none">
<div class="card-body">
<h5 class="card-title text-dark">
{{article.title}}
</h5>
<p class="mb-1 text-muted small">{{ article.body|truncatechars:150 }}</p>
</div>
</a>
</div>
{% empty %}
<div class="list-group-item text-center text-muted">
<p class="my-3">没有找到匹配的文章</p>
</div>
{% endfor %}
</div>
</div>
{% endblock %}最终实现的效果如下所示:
