Django-haystack插件實現
項目地址:https://github.com/ylpxzx/lifeblog
步驟
- 安裝依賴包
pip install whoosh,jieba,django-haystack
# 儘量採用其他源的pip進行安裝,比如
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple django-haystack
- 將haystack加入INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
...
'post',
'haystack', #添加該行
]
- 在需要搜索的應用app下創建search_indexes.py,如在post應用下。
from haystack import indexes
from .models import Post
# 類名的命名規則是固定的,嚴格按照“應用名+Index”
class PostIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True,template_name='search/indexes/post/post_text.txt')
def get_model(self):
return Post
def index_queryset(self, using=None):
return self.get_model().objects.all()
-
將site-packages/haystack/backends/whoosh_backend.py複製到應用app下,並更名爲whoosh_cn_backend.py
-
在settings.py中設置haystack配置
# 配置搜索設置
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'post.whoosh_cn_backend.WhooshEngine', # post應用下的whoosh_cn_backend.py文件
'PATH': os.path.join(BASE_DIR, 'whoosh_index'), # 指定了索引文件需要存放的位置,我們設置爲項目根目錄 BASE_DIR 下的 whoosh_index 文件夾(在建立索引時會自動創建)。
},
}
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 6 # 指定如何對搜索結果分頁,這裏設置爲每 6 項結果爲一頁。
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' # 指定什麼時候更新索引,這裏我們使用 haystack.signals.RealtimeSignalProcessor,作用是每當有文章更新時就更新索引。由於博客文章更新不會太頻繁,因此實時更新沒有問題。
- 創建template/search/indexes/app_name/model_text.txt文件,建立指定的字段索引
# 如:創建template/search/indexes/post/post_text.txt
{{ object.title }}
{{ object.content }}
- 創建索引,自動生成whoosh_index文件夾
# 創建索引
python manage.py rebuild_index # 輸入y即可
# 更新索引
python manage.py update_index
- 在應用app的views.py下繼承SearchView
from haystack.views import SearchView
from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger
from django.conf import settings
from django.shortcuts import render,redirect
from django.db.models import Q
class MySearchIndex(SearchView):
# template = 'search.html'
def extra_context(self):
context = super(MySearchIndex,self).extra_context()
context['category_list'] = Category.objects.all().order_by('post_category')
context['popular_post'] = Post.objects.all().order_by('-total_views')[:4]
return context
def create_response(self):
if self.request.GET.get('q'):
# print("進入not self.request")
keyword = self.request.GET.get('q')
# post_info = Post.objects.filter(title__contains=keyword)
post_info = Post.objects.filter(Q(title__icontains=keyword)|Q(content__icontains=keyword)).order_by("id") # 搜索標題和文章內容
# post_info = Post.objects.all()
paginator = Paginator(post_info, settings.HAYSTACK_SEARCH_RESULTS_PER_PAGE)
try:
page = paginator.page(int(self.request.GET.get('page', 1)))
except PageNotAnInteger:
page = paginator.page(1)
except EmptyPage:
page = paginator.page(paginator.num_pages)
context = {
'query': self.query,
'form': self.form,
'page': page,
'paginator': paginator,
'suggestion': None,
}
context.update(self.extra_context())
return render(self.request, self.template, context)
else:
qs = super(MySearchIndex, self).create_response()
# print(self.get_context())
return qs
- 在應用urls下配置路由
url(r'^search/$', MySearchIndex(), name='haystack_search'),
- 創建template/search/search.html文件
{% extends 'index.html' %}
{% block Banner %}{% endblock %}
{% block area %}
<div class="col-lg-8">
<div class="blog_left_sidebar">
<div class="row">
{% for post in page.object_list %}
<div class="col-md-6">
<article class="blog_style1 small">
<div class="blog_img">
<img class="img-fluid" style="height: 280px;" src="/media/{{ post.cover }}" alt="">
</div>
<div class="blog_text">
<div class="blog_text_inner">
<div class="cat">
<a class="cat_btn" href="#">{{ post.category }}</a>
<a href="#"><i class="fa fa-calendar" aria-hidden="true"></i> {{ post.create_time|date:"Y-m-d" }}</a>
<a href="#"><i class="fa fa-comments-o" aria-hidden="true"></i> 05</a>
</div>
<a href="{% url 'post:detail' post.id %}" ><h4>{{ post.title }}</h4></a>
<p>{{ post.short_detail|safe }}</p>
<a class="blog_btn" href="{% url 'post:detail' post.id %}">Read More</a>
</div>
</div>
</article>
</div>
{% empty %}
<h3>沒有找到相關文章</h3>
{% endfor %}
</div>
<!-- 分頁欄 -->
<nav class="blog-pagination justify-content-center d-flex">
<ul class="pagination">
{% if page.has_previous %}
<li class="page-item">
<a href="{% url 'post:haystack_search' %}?q={{ query }}&page={{ page.previous_page_number }}" class="page-link" aria-label="Previous">
<span aria-hidden="true">
<span class="lnr lnr-chevron-left"></span>
</span>
</a>
</li>
{% else %}
<li class="page-item">
<a href="#" class="page-link" aria-label="Previous">
<span aria-hidden="true">
<span class="lnr lnr-chevron-left"></span>
</span>
</a>
</li>
{% endif %}
{% for num in page.paginator.page_range %}
{% if num == page.number %}
<li class="page-item active"><a href="{% url 'post:haystack_search' %}?q={{ query }}&page={{ num }}" class="page-link">{{ num }}</a></li>
{% else %}
<li class="page-item"><a href="{% url 'post:haystack_search' %}?q={{ query }}&page={{ num }}" class="page-link">{{ num }}</a></li>
{% endif %}
{% endfor %}
{% if page.has_next %}
<li class="page-item">
<a href="{% url 'post:haystack_search' %}?q={{ query }}&page={{ page.next_page_number }}" class="page-link" aria-label="Next">
<span aria-hidden="true">
<span class="lnr lnr-chevron-right"></span>
</span>
</a>
</li>
{% else %}
<li class="page-item">
<a href="#" class="page-link" aria-label="Next">
<span aria-hidden="true">
<span class="lnr lnr-chevron-right"></span>
</span>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
{% endblock %}
網上示例需要在字段選取中間加個object,如:
<p>{{ post.object.short_detail|safe }}</p>
項目文件結構
異常解決
- ImportError: cannot import name ‘six’ from ‘django.utils’
- 安裝six
pip install six
- 將six.py複製到django/utils
文件路徑
site-packages/six.py
site-packages/django/utils
- ImportError: cannot import name python_2_unicode_compatible
- 報錯位置導入的包替代爲以下導入語句
from django.utils.six import python_2_unicode_compatible