Whoosh全文检索-Django配置
(https://django-haystack.readthedocs.io/en/master/tutorial.html#installation "haystack文档参考")
一. 安装
pip install django-haystack
pip install whoosh
pip install jieba
二. 配置
- 创建一个新的app, 并在app目录下创建
search_indexes.py 名字固定写法
from haystack import indexes
from article.models import Articles # 需要索引的模型
# 创建索引的文件
class ArticleIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True) # 索引只能一个字段
def get_model(self):
return Articles
def index_queryset(self, using=None):
return self.get_model().objects.all() # 返回
- settings.py文件配置
INSTALLED_APPS = [
...
'articles'
'search_index', # 新创建的app
'haystack', # 分词器
...
]
# 分词器配置
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine', # 指定使用的分词语言
'PATH': os.path.join(BASE_DIR, 'whoosh_index') # 指定创建索引保存的位置, 会自动创建
}
}
# 自动更新索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
三. 添加路由, 路由
主路由配置urls.py
from django.urls import path, include, re_path
urlpatterns = [
...
path('', include('article.urls')),
path('search_index/', include('search_index.urls')), # 新建的App
path('search/', include('haystack.urls')), # 全文检索模块注册
...
]
新App路由urls.py
from django.urls import path
from .views import MySearchView
urlpatterns = [
path('search/test/', MySearchView(), name='haystack_search')
]
新APP视图views.py
from haystack.views import SearchView
from django.http import HttpResponse
from django.core.paginator import Paginator
class MySearchView(SearchView):
def build_page(self):
print('进入搜索页面:')
# 分页重写
context = super(MySearchView, self).extra_context() # 继承自带的context
try:
page_no = int(self.request.GET.get('page', 1))
except Exception:
return HttpResponse("Not a valid number for page.")
if page_no < 1:
return HttpResponse("Pages should be 1 or greater.")
a = []
for i in self.results:
a.append(i.object)
paginator = Paginator(a, 18)
# print("--------")
# print(page_no)
page = paginator.page(page_no)
print('搜索的商品信息:', page)
return (paginator, page)
def extra_context(self):
context = super(MySearchView, self).extra_context() # 继承自带的context
context['title'] = '搜索'
return context
给whoosh添加中文检索配置 在模块haystac.backends目录下创建 ChineseAnalyzer.py文件
import jieba
from whoosh.analysis import Tokenizer, Token
class ChineseTokenizer(Tokenizer):
def __call__(self, value, positions=False, chars=False,
keeporiginal=False, removestops=True,
start_pos=0, start_char=0, mode='', **kwargs):
t = Token(positions, chars, removestops=removestops, mode=mode,
**kwargs)
seglist = jieba.cut(value, cut_all=True)
for w in seglist:
t.original = t.text = w
t.boost = 1.0
if positions:
t.pos = start_pos + value.find(w)
if chars:
t.startchar = start_char + value.find(w)
t.endchar = start_char + value.find(w) + len(w)
yield t
def ChineseAnalyzer():
return ChineseTokenizer()
在当前目录下复制一份whoosh_backend.py文件 名改名为whoosh_cn_backend.py再修改里内容
添加
from .ChineseAnalyzer import ChineseAnalyzer
替换
analyzer = StemmingAnalyzer()
换为
analyzer = ChineseAnalyzer()
四. 添加模板
索引模板固定写法. /templates/search/indexes/注册时的APP名字/创建索引用的模型名字小写_text.txt /templates/search/indexes/article/articles_text.txt
{{ object.title }}
{{ object.content }}
HTML模板固定写法 /templates/search/search.html
<ul class="goods_type_list clearfix">
{% for result in page.object_list %}
<li>
<a href="/goods/detail/{{ result.object.id }}/"><img src="/upload/{{ result.object.gpic }}"></a>
<h4><a href="/detail/{{ result.object.id }}/">{{ result.object.gtitle }}</a></h4>
<div class="operate">
<span class="prize">{{ result.object.gprice }}</span>
<span class="unit">{{ result.object.gprice }}/{{ result.object.gunit }}</span>
<a href="/cart/add{{result.object.id}}_1/" class="add_goods" title="加入购物车"></a>
</div>
</li>
{% endfor %}
</ul>
<div class="pagenation">
{% if page.has_previous %}
<a href="/search?q={{query}}&page={{page.previous_page_number}}"><上一页</a>
{% else %}
<a href="/search?q={{ query }}"><上一页</a>
{% endif %}
{% if page.number <= 5 %} <!--当前页面数小于5时-->
{% for page_num in paginator.page_range %}
{%if forloop.counter <= 5 %}
<a href="/search?q={{query}}&page={{page_num}}"
{% if page.number == page_num %}
class="active"
{% endif %}
>{{ page_num }}</a>
{%endif%}
{% endfor %}
{% else %}
{% if page.number|add:1 > paginator.num_pages %}
<a href="/search?q={{query}}&page={{page.number|add:-4}}">{{ page.number|add:-4}}</a>
{% endif %}
{% if page.number|add:2 > paginator.num_pages %}
<a href="/search?q={{query}}&page={{page.number|add:-3}}">{{ page.number|add:-3}}</a>
{% endif %}
<a href="/search?q={{query}}&page={{page.number|add:-2}}" >{{ page.number|add:-2}}</a>
<a href="/search?q={{query}}&page={{page.number|add:-1}}">{{ page.number|add:-1}}</a>
<a href="/search?q={{query}}&page={{page.number}}" class="active">{{ page.number }}</a>
{% if page.number|add:1 <= paginator.num_pages %}
<a href="/search?q={{query}}&page={{page.number|add:1}}">{{ page.number|add:1}}</a>
{% endif %}
{% if page.number|add:2 <= paginator.num_pages %}
<a href="/search?q={{query}}&page={{page.number|add:2}}">{{ page.number|add:2}}</a>
{% endif %}
{% endif %}
{% if page.has_next %}
<a href="/search?q={{query}}&page={{page.next_page_number}}">下一页></a>
{% else %}
<a href="/search?q={{query}}&page={{paginator.num_pages}}">下一页></a>
{% endif %}
</div>
</div>
五. 迁移生成索引文件
python manage.py rebuild_index
# 可选(更新)
python manage.py update_index
6. 测试
/search/p=xxxxx