引言
最近要做一個項目,要用到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了,所以這次寫的東西估計也有很多不太完善的地方,還希望大家多多批評指正,謝謝大家