上一章记录了通过model自带的搜索接口功能实现简单的搜索。
这一章节,来写一下通过第三方应用包来做到的高级全文搜索.
我们需要用到的应用是django-haystack
1: 安装应用
首先安装django-haystack,切记安装以后再setting里面设置的时候,把他设置在你自定义的所有app之前。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'haystack', #在所有app的首个
'mainsite',
'team',
'users',
'likes',
'test_area',
'mdeditor',
'crispy_forms',
]
除了上面的配置,还需要在settings文件里设置如下
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
},
}
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 10
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
接着再安装相关的一些依赖包
Whoosh。Whoosh 是一个由纯 Python 实现的全文搜索引擎,没有二进制文件等,比较小巧,配置简单方便。
jieba 中文分词。由于 Whoosh 自带的是英文分词,对中文的分词支持不是太好,所以使用 jieba 替换Whoosh 的分词组件。
2:进行数据设定
打个比方,我的应用里,有一个model是Article,代表的是所有用户发布的文章
我现在想对这个内容进行搜索,我想搜索“abc”,但是不仅包括搜索文章标题,还想要把文章内容里包含“abc”的article找出来。
Article这个model属于我的项目里的mainsite这个app,需要我们在这个app下面创建如下文件search_indexes.py
而内容,则是写为如下
from haystack import indexes
from .models import Article,Team
class ArticleIndex(indexes.SearchIndex,indexes.Indexable):
#一个索引类里,必须要有也只能有一个字段,设置为document=True,use_template=True
text = indexes.CharField(document=True,use_template=True)
def get_model(self):
return Article
def index_queryset(self, using=None):
return self.get_model().objects.all()
这个类的命名是有规则的,是Modename + Index
组成的
document=True意味着搜索引擎将以这个字段的内容来进行检索.
user_template=True意味着你可以在下面将会提到的索引文件.txt中自定义你想要搜索的区域,比如同时在内容和标题里搜索。
所以我们在templates/search/indexes/youapp/\
这样的路径下需要创建以上格式的txt文件以存放你需要自定义的搜索区域。
{{ object.article_title }}
{{ object.article_content }}
这样就表示我想在标题和内容里同时搜索我输入的关键字
3: 路由URL配置
在项目的urls里面设置如下
urlpatterns = [
......
path('search/',include('haystack.urls')),
]
千万记得不要在自己的app里设置search这个路由path了
4:前端页面
主页上面写的搜索输入框
设置的search.html前端页面
{% if query %}
搜索结果如下
{% for result in page.object_list %}
{{result.object.article_title}}
{% empty %}
No result found.
{% endfor %}
{% if page.has_previous or page.has_next %}
{% if page.has_previous %}{% endif %}« Previous{% if page.has_previous %}{% endif %}
|
{% if page.has_next %}{% endif %}Next »{% if page.has_next %}{% endif %}
{% endif %}
{% else %}
请输入关键字
{% endif %}
在主页的搜索输入框前端页面这里踩了个巨坑,所有东西都调试完了,搜索以后就是没有结果显示,查看了代码,发现是{% if query %}
这个条件没有满足,查看文档,发现query这个变量其实是用户输入的查询关键字,但是我明明已经输入了,但是为什么没有呢?
曾经尝试把method更改为post,也没有用,后来我想是不是取值没有取到,结果去haystack的源码一看,竟然他的取值是取得name=q的内容,如下。
def get_query(self):
"""
Returns the query provided by the user.
Returns an empty string if the query is invalid.
"""
if self.form.is_valid():
return self.form.cleaned_data['q']
return ''
我之前在写输入框的时候,name写的是“search_info”,现在改为q以后,马上就生效了。
5:效果图
6:搜索结果URL问题
最后,还碰到一个小问题,就是搜索出来的结果,超链接的地址是不对的,他连接的是 http://127.0.0.1:8000/search/?q=function
而非每篇文章的页面,问题出在哪里呢?
出在get_absolute_url这个方法上,因为我们其实没有定义过get_absolute_url这个方法,故我们去Article这个模型中去定义。
class Article(models.Model):
......
def get_absolute_url(self):
return reverse('team:article_detail',args=[str(self.article_id)])
于是,就让搜索结果指向了模型案例本身页面。
这样,就大功告成了,这是英语的搜索,下一篇继续讲中文的搜索.
参考资料:
https://www.zmrenwu.com/courses/django-blog-tutorial/materials/27/
https://django-haystack.readthedocs.io/en/master/tutorial.html