一、搜索功能分析
思考:如果我们要做一个通过关键词搜索文章的功能,需要搜索哪些字段,以及使用什么技术方案?
搜索字段:
1,字段
2,内容
3,作者
技术方案:
1,mysql的模糊查询%like%
1,优点:实现起来简单
2,缺点:数据量比较大的情况下,查询效率极低
2,全文检索引擎
1,优点:专业的全文检索引擎,效率高
2,缺点:实现起来比较复杂
选择使用全文检索引擎,自行实现django框架和全文检索引擎的代码比较麻烦,选用django的
第三方包djangohaystack。它支持多钟全文检索引擎,本项目选择最流行的全文检索引擎之一
elasticsearch
二、elasticsearch介绍
elasticsearch原理:http://developer.51cto.com/art/201904/594615.htm
三、docker介绍
1.docker介绍与安装
~介绍
1,什么是docker?
~简化创建,部署,运行应用程序的一个工具
~打包应用程序所需的库和依赖环境
~精简的虚拟机
2.为什么使用docher?
流行、方便、强大
3.docker vs 虚拟机
体积更小、运行更快、集成扩展更好
4.docker架构
~架构
~客户端
~守护进程
~仓库
~docker对象
~镜像 精简linux
~容器
~服务
~docker Hub
安装
官方安装文档:https://www.docker.com/
lsb_release -a #查看系统信息
五、新闻搜索功能实现
1,业务流程分析
判断是否传递查询参数q
如果没有传递q,则直接返回热门新闻数据
如果没有传递,则返回查询结果
2,接口设计
1.接口说明:
类目 说明
请求方法 GET
url定义 /news/search/
参数格式 查询参数
2.参数说明:
参数名 类型 是否必须 描述
q 字符串 否 查询的关键字
page 整数 否 页码
3.返回结果:
搜索页面html
1.创建haystack数据模型
news/search_indexes 文件代码
from haystack import indexes
from .models import News
class NewsIndex(indexes.SearchIndex, indexes.Indexable):
"""
这个模型的作用类似于django的模型,它告诉haystack哪些数据会被
放到查询返回的模型对象中,以及通过哪些字段进行索引和查询
"""
text = indexes.CharField(document=True, use_template=True)
id = indexes.CharField(model_attr='id')
title = indexes.CharField(model_attr='title')
digest = indexes.CharField(model_attr='digest')
content = indexes.CharField(model_attr='content')
image_url = indexes.CharField(model_attr='image_url')
def get_model(self):
"""
返回建立索引的模型
:return:
"""
return News
def index_queryset(self, using=None):
"""
返回要建立索引的数据查询集
:param using:
:return:
"""
return self.get_model().objects.filter(is_delete=False)
2,创建索引数据模版
templates/search/indexes/news/news_text.txt 文件
{{ object.title }}
{{ object.digest }}
{{ object.content }}
{{ object.author.username }}
3,创建索引
虚拟机进入项目根目录
运行命令:python manage.py -h
python manage.py rebuild_index
代码:
news/templatetags/news_template_filters.py
from django import template
register = template.Library()
@register.filter()
def page_bar(page):
page_list = []
if page.number != 1:
page_list.append(1)
if page.number - 3 > 1:
page_list.append('...')
if page.number - 2 > 1:
page_list.append(page.number - 2)
if page.number - 1 > 1:
page_list.append(page.number -1)
page_list.append(page.number)
if page.paginator.num_pages > page.number + 1:
page_list.append(page.number + 1)
if page.paginator.num_pages > page.number + 2:
page_list.append(page.number + 2)
if page.paginator.num_pages > page.number + 3:
page_list.append('...')
if page.paginator.num_pages != page.number:
page_list.append(page.paginator.num_pages)
return page_list
apps/news/views.py 代码
class NewsSearchView(SearchView):
"""
新闻搜索视图
url: /news/search/
"""
# 配置搜索模板文件
template_name = 'news/search.html'
def get(self, request, *args, **kwargs):
# 1. 获取查询参数
query = request.GET.get('q')
if not query:
# 2. 如果没有查询数
# 返回热门新闻
hot_news = HotNews.objects.select_related('news__tag').only('news__title', 'news__image_url', 'news_id', 'news__tag__name').filter(is_delete=False).order_by('priority', '-news__clicks')
# 分页
paginator = Paginator(hot_news, settings.HAYSTACK_SEARCH_RESULTS_PER_PAGE)
try:
page = paginator.get_page(int(request.GET.get('page')))
except Exception as e:
page = paginator.get_page(1)
return render(request, self.template_name, context={
'page': page,
'query': query
})
else:
# 3. 如果有怎么办
return super().get(request, *args, **kwargs)
def get_context_data(self, *args, **kwargs):
"""
在context中添加变量page
:param args:
:param kwargs:
:return:
"""
context = super().get_context_data(*args, **kwargs)
if context['page_obj']:
context['page'] = context['page_obj']
return context