引言
最近要做一个项目,要用到Django了,才发现自己已经忘了好多Django的相关知识了,这次趁着这个项目也复习一下,本篇文章主要是django+haystack+whoosh实现全文检索及关键字高亮,话不多说,我们这就开始。
Django
Django是一个开放源代码的Web应用框架,由Python写成。采用了MTV的框架模式,即模型M,视图V和模版T。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统)软件。目前Django 3. 0已经发布了,但是为了照顾到大多数的同学,本次项目还是Django 2.2 版本,当然原理什么的都是相同的,至于Django安装和美化大家请移步我的另外一篇博客,Django后台不好看?变美只需一步,这里就不再详细介绍了。
Haystack
现在搜索是一个日益流行的话题,虽然Django的admin也有自带的搜索功能,但是由于其可定制化的程度太低等原因,大家还是更愿意来进行自定义,这就导致了Haystack等工具的产生,Haystack试图整合自定义搜索,使开发者们可以尽可能简单的灵活和强大到足以处理更高级的用例。另外haystack支持多种搜索引擎,不仅仅是whoosh,使用solr、elastic search等搜索,也可通过haystack,而且直接切换引擎即可,甚至无需修改搜索代码。
whoosh
一个由纯Python编写的全文搜索引擎,虽然性能比不上sphinx、Xapian、Elasticsearch等,但是whoosh无二进制包,程序不会莫名其妙的崩溃,对于小型的站点,whoosh已经足够使用。
jieba
一款中文分词词库
安装
说是haystack,但是安装的时候安装的是Django-haystack,如果安装haystack是会报错的,如果你不小心装错了请记得卸载它。下面给出pip安装代码,如果还不会pip配置国内镜像的可以评论或私信,我再出一篇文章。
pip install django-haystack
pip install whoosh
pip install jieba
配置
首先在installed app里面添加haystack。
INSTALLED_APPS = [
'simpleui',
'haystack',
'Drug',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
然后同样在settings.py中继续配置Haystack。
HAYSTACK_CONNECTIONS = {
'default': {
# 设置haystack的搜索引擎
'ENGINE': 'Drug.whoosh_cn_backend.WhooshEngine',
# 设置索引文件的位置
'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
}
}
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 20
# 自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
注意我的搜索引擎那里设置的是whoosh_cn_backend.WhooshEngine,这个在下面会提到,现在先这么写就行。
代码
首先就是在你的应用目录(即要设为检索关键字的应用目录下)下新建一个search_indexes.py文件(名字是固定的不能改,改了就不能用)。如下可作参考。
[图片上传失败...(image-aaf997-1595385034186)]
search_index.py的内容如下,一般也是不需要变动的。
class MedicineIndex(indexes.SearchIndex,indexes.Indexable):
text = indexes.CharField(document=True,use_template=True)
def get_model(self):
return Medicine
def index_queryset(self, using=None):
return self.get_model().objects.all()
当然类名需要根据自己的类来命名。
再然后根据参考下图在templates文件夹下新建几层文件,如templates/search/indexes/应用名/model名_text.txt,如下图所示。
[图片上传失败...(image-a5d5c7-1595385034186)]
txt文件的内容就是你想进行搜索的字段名,参考如下格式。
之后就是配置urls中的地址。
from django.urls import path, include
urlpatterns = [
# 其它path设置
path(r'search/', include('haystack.urls')),
# django小于 2.0版本的用以下的url
# url(r'^search/', include('haystack.urls')),
]
再然后就是创建用来显示的html文件,这个是需要自己定制的,下面给出我的来参考一下,这个是加入了高亮关键词和一些样式的最终版本。有关高亮关键词的部分,几句话就可以完成。
首先是要在文件头写上{% load highlight %}
然后就是在你要高亮的那个字段写上{% highlight result.object.source with query max_length 1000 %}。
那个max_length是最大长度,但是在DJango3.0好像不能用,大家有知道为什么的可以评论或者私信讨论一下。
<!DOCTYPE html>
<html>
{% load highlight %}
{#{% highlight result.summary with query html_tag "div" css_class "highlighted" %}#}
<head>
<title>test</title>
{#搜索框样式#}
<style>
span.highlighted {
color: red;
font-size: x-large;
}
</style>
<style type="text/css">
input{
width: 200px;
border: 1px solid #e2e2e2;
height: 30px;
float: left;
background-repeat: no-repeat;
background-size: 25px;
background-position:5px center;
padding:0 0 0 40px;
}
#search{
width: 78px;
height: 32px;
float: left;
background: black;
color: white;
text-align: left;
line-height: 32px;
cursor: pointer;
}
</style>
</head>
{#<link rel = “stylesheet” type = “text/css” href = “style.css” />#}
<body>
{% load highlight %}
<form method='get' action="/search" target="_self" style="vertical-align: middle">
<p><input type="text" name="q" placeholder="请输入关键字" style="width:300px; height:38px; vertical-align:middle; bordercolor:#1E90FF; "/></p>
<p><input type="submit" value="查询" id="search" style="background:#1E90FF; color:#FFFFFF; border:none;
width:100px; height:40px; margin-left:-5px; vertical-align:middle;"/> </p>
<br>
</form>
{% if query %}
{% load highlight %}
{# {% highlight result.object.title with query %}#}
{# {% highlight result.object.body with query %}#}
{% for result in page.object_list %}
<a href="/{{ result.object.id }}/">
<div class="media">
<div class="media-left">
</div>
<div class="media-body" >
<p>
<h4 class="list-group-item-heading">{% highlight result.object.name with query %}</h4></p>
<p class="list-group-item-text">source:{% highlight result.object.source with query max_length 1000 %}</p>
<p class="list-group-item-text">type:{% highlight result.object.type with query max_length 1000 %}</p>
<p class="list-group-item-text">include:{% highlight result.object.include with query max_length 1000 %}</p>
<p class="list-group-item-text">function:{% highlight result.object.function with query max_length 1000 %}</p>
<p class="list-group-item-text">focus:{% highlight result.object.focus with query max_length 1000 %}</p>
</div>
</a><br/>
{% empty %}
<p>不存在符合的搜索结果</p>
{% endfor %}
{% 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 %}
{% endif %}
</body>
</html>
注意到我在代码那个大标题上面加粗的话,如果你看了其他的相关文章应该会发现不一样,我的好像少了一些东西,其实是我简化了一些,直接在你的应用文件夹下面新建whoosh_cn_backend.py文件即可,文件的内容如下。额,文件实在太长了,为了不影响大家的阅读体验和赚点积分,大家可以到这下载。
写在最后
到这里就以及全部完成了,是不是就像我说的那么简单,如果还有不太明白的地方,大家一起交流哈。
因为是好久没有碰过Django了,所以这次写的东西估计也有很多不太完善的地方,还希望大家多多批评指正,谢谢大家