假设你已掌握了djangorestframework
的基本用法
安装 haysyack
, whoosh
, jieba
#Ubuntu系统
sudo pip3 install django-haystack whoosh jieba
#windows
pip install django-haystack whoosh jieba -i https://pypi.tuna.tsinghua.edu.cn/simple/
#settings.py
INSTALLED_APPS = [
...
'haystack',
]
# 配置全文搜索
# 指定搜索引擎
HAYSTACK_CONNECTIONS = { # 指定搜索引擎
'default': {
'ENGINE': 'prod.whoosh_cn_backend.WhooshEngine', # whoosh_cn_backend 需自定义。
'PATH': os.path.join(BASE_DIR, 'whoosh_index'), # 索引文件存放的目录,建立索引时自动创建
},
}
# 设置为每 10 项结果为一页,默认是 20 项为一页
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 10
# 当数据库改变时,自动更新索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
whoosh_cn_backend
# 在prod下创建whoosh_cn_backend.py
# 复制 site-packages\haystack\backends\whoosh_backend.py 中的内容,替换分词模块
# 在最上面导入 ChineseAnalyzer
from jieba.analyse import ChineseAnalyzer
# 搜索 StemmingAnalyzer 替换为 ChineseAnalyzer
#myapp>search_indexes.py 创建search_indexes.py文件(文件名不可以改)
from prod.models import GoodsModel # 导入数据模型类
from haystack import indexes
# 创建一个索引类
class BookIndex(indexes.SearchIndex, indexes.Indexable):
# 固定语句,惯例使用’text‘命名字段
text = indexes.CharField(document=True, use_template=True)
# document=True,说明搜索引擎使用该字段内容作为索引来检索,只能有一个字段具有该属性True
# use_template=True 使用模板建立索引
# 换名字的时候,注意配置HAYSTACK_DOCUMENT_FIELD = "XXX"
def get_model(self): # 必须
return GoodsModel
def index_queryset(self, using=None):
"""Used when the entire index for model is updated."""
return self.get_model().objects.all()
# 创建 templates/search/indexes//_text.txt 文件
# 写入如下内容:
{{ object.sku_name }} # 必须object。后面为模型类要建立索引的字段
{{ object.title }}
{{ object.instruction }}
from django.urls import path, re_path
urlpatterns = [
...,
re_path(r"search/$", views.SearchView.as_view()),
]
# 任意views.py 文件
import json
from django.conf import settings
from django.core.paginator import InvalidPage, Paginator
from django.http import Http404, HttpResponse, JsonResponse
from haystack.forms import ModelSearchForm
from haystack.query import EmptySearchQuerySet
# 获取配置的每页数据。没有配置默认20
RESULTS_PER_PAGE = getattr(settings, 'HAYSTACK_SEARCH_RESULTS_PER_PAGE', 20)
class SearchView(APIView):
# 必须为get方法
def get(self, request, load_all=True, form_class=ModelSearchForm, searchqueryset=None, extra_context=None,
results_per_page=None):
query = ''
results = EmptySearchQuerySet()
if request.GET.get('q'):
form = form_class(request.GET, searchqueryset=searchqueryset, load_all=load_all)
if form.is_valid():
query = form.cleaned_data['q']
results = form.search()
else:
form = form_class(searchqueryset=searchqueryset, load_all=load_all)
paginator = Paginator(results, results_per_page or RESULTS_PER_PAGE)
try:
p = int(request.GET.get('page', 1))
page = paginator.page(p)
except InvalidPage:
return Response({
"code": 404,
"msg": "无搜索结果"
})
context = {
'form': form,
'page': page,
'paginator': paginator,
'query': query,
'suggestion': None,
}
if results.query.backend.include_spelling:
context['suggestion'] = form.get_suggestion()
if extra_context:
context.update(extra_context)
return Response({
"code": 200,
"msg": "搜索成功",
"data": [{
"id": i.object.id,
"sku_name": i.object.sku_name,
"price": i.object.price,
"selling_price": i.object.selling_price,
"img": i.object.img,
"title": i.object.title,
"instruction": i.object.instruction,
"count": i.object.count,
"stock": i.object.stock,
"online": i.object.online,
} for i in page.object_list],
"page": p,
"count": paginator.count,
})
#模型类已存储数据的情况下
#每次更新索引相关内容都要重建索引,将数据同步到搜索引擎
python manage.py rebuild_index
#将数据库的数据---->同步到搜索引擎
#查询时,从搜索引擎 查询数据,比模糊查询更高效
# http://127.0.0.1:8000/prod/search/?q=电视&page=1