首页 科技正文

欧博开户:第 11 篇:基于 drf-haystack 的文章搜索接口

admin 科技 2020-07-03 41 0

作者:HelloGitHub-追梦人物

在 django 博客教程中,我们使用了 django-haystack 和 Elasticsearch 举行文章内容的搜索。django-haystack 默认返回的搜索效果是一个类似于 django QuerySet 的工具,需要配合模板系统使用,由于未被序列化,以是无法直接用于 django-rest-framework 的接口。固然解决方案也很简朴,编写响应的序列化器将返回效果序列化就可以了。

然则,通过之前的功效我们看到,使用 django-rest-framework 是一个近乎尺度化但又死板无聊的历程:首先是编写序列化器用于序列化资源,然后是编写视图集,提供对资源各种操作的接口。既然是尺度化的器械,一定已经有人写好了相关的功效以供复用。此时就要施展开源社区的气力,去 GitHub 使用要害词 rest haystack 搜索,果真搜到一个 drf-haystack 开源项目,专门用于解决 django-rest-framework 和 haystack 连系使用的问题。因此我们就不再重复造轮子,直接使用开源第三方库来实现我们的需求。

既然要使用第三方库,第一步固然是安装它,进入项目根目录,运行:

$ pipenv install drf-haystack

由于需要使用到搜索功效,因此需要启动 Elasticsearch 服务,最简朴的方式就是使用项目中编排的 Elasticsearch 镜像启动容器。

项目根目录下运行如下下令启动所有项目所需的容器服务:

$ docker-compose -f local.yml up --build

启动完成后运行 docker ps 下令可以检查到如下 2 个运行的容器,说明启动乐成:

hellodjango_rest_framework_tutorial_local
hellodjango_rest_framework_tutorial_elasticsearch_local

接着建立一些文章,以便用于搜索测试,可以自己在 admin 后台添加,固然最简朴的方式是运行项目中的 fake.py 剧本,批量天生测试数据:

$ docker-compose -f local.yml run --rm hellodjango.rest.framework.tutorial.local python -m scripts.fake

测试文章天生后,还要运行下面的下令给文章的内容建立索引,这样搜索引擎才气凭据索引搜索到响应的内容:

$ docker-compose -f local.yml run --rm hellodjango.rest.framework.tutorial.local python manage.py rebuild_index

# 输出如下
Your choices after this are to restore from backups or rebuild via the `rebuild_index` command.
Are you sure you wish to continue? [y/N] y
Removing all documents from your index because you said so.
All documents removed.
Indexing 201 文章
GET /hellodjango_blog_tutorial/_mapping [status:404 request:0.005s]

注重

若是天生索引时看到如下错误:

elasticsearch.exceptions.ConnectionError: ConnectionError(<urllib3.connection.HTTPConnection object at 0x7f25daa83c50>: Failed to establish a new connection:
[Errno -2] Name does not resolve) caused by: NewConnectionError(<urllib3.connection.HTTPConnection object at 0x7f25daa83c50>: Failed to establish a new connection: [Errno -2] Name does not resolve)

这是由于项目设置中 Elasticsearch 服务的 URL 设置失足导致,解决方式是进入 settings/local.py 设置文件中,将搜索设置改为下面的内容:

HAYSTACK_CONNECTIONS['default']['URL'] = 'http://elasticsearch.local:9200/'

由于这个 URL 地址需和容器编排文件 local.yml 中指定的容器服务名一致 Docker 才气准确剖析。

现在万事具备了,数据库中已经有了文章,搜索服务已经有了文章的索引,只需要守候客户端来举行查询,然后返回效果。以是接下来就进入到 django-rest-framework 尺度开发流程:界说序列化器 -> 编写视图 -> 设置路由,这样一个尺度的搜索接口就开发出来了。

先来界说序列化器,粗略过一遍 drf-haystack 官方文档,依葫芦画瓢建立文章(Post) 的 Serializer

blog/serializers.py

from drf_haystack.serializers import HaystackSerializerMixin


class PostHaystackSerializer(HaystackSerializerMixin, PostListSerializer):
    class Meta(PostListSerializer.Meta):
        search_fields = ["text"]

凭据官方文档的先容,为了复用已经界说好用于序列化文章列表的序列化器,我们直接继续了 PostListSerializer,同时我们还混入了 HaystackSerializerMixin,这是 drf-haystack 的混入类,提供搜索效果序列化相关的功效。

另外内部类 Meta 同样继续 PostListSerializer.Meta,这样就无需重复界说序列化字段列表 fields。要害的地方在这个 search_fields,这个列表声明用于搜索的字段(通常都界说为索引字段),我们在上一部教程设置 django-haystack 时,文章的索引字段设置的名字叫 text,若是对这一块有疑惑,可以简朴回首一下 Django Haystack 全文检索与要害词高亮 中的内容。

然后编写视图集,需继续 HaystackViewSet

blog/views.py

from drf_haystack.viewsets import HaystackViewSet
from .serializers import PostHaystackSerializer

class PostSearchView(HaystackViewSet):
    index_models = [Post]
    serializer_class = PostHaystackSerializer

这个视图集异常简朴,只需要通过类属性 index_models 声明需要搜索的模子,以及搜索效果的序列化器就行了,剩余的功效均由 HaystackViewSet 内部替我们实现了。

最后是在路由器中注册视图集,自动天生 URL 模式:

blogproject/urls.py

router = routers.DefaultRouter()
router.register(r"search", blog.views.PostSearchView, basename="search")

搞定了!一套尺度化的 django-restful-framework 开发流程,不外大量事情已由 drf-haystack 在背后替我们完成,我们只写了异常少量的代码即实现了一套搜索接口。

来看看搜索效果。我们启动 Docker 容器,在浏览器输入如下花样的 URL:

http://127.0.0.1:8000/api/search/?text=key-word

将 key-word 替换为需要搜索的要害字,例如将其替换为 markdown,测试集数据中获得的搜索效果如下:

搜索效果相符预期,但略微有一点不太好的地方,就是没有高亮的题目和摘要,我们希望未来显示的效果应该是下面这样的,因此返回的数据必须支持这样的显示:

要害词高亮的实现原理实在异常简朴,通过剖析整段文本,将搜索要害词替换为由 HTML 标签包裹的富文本,并给这个包裹标签设置 CSS 样式,让其显示差别的字体颜色就可以了。

领会其原理后固然就是实现其功效,不外 django-haystack 已经为我们造好了轮子,而且在上一部教程的 Django Haystack 全文检索与要害词高亮,我们还对默认的高亮辅助类举行了革新,优化了文章题目被从要害字位置截断的问题,因此我们使用革新后的辅助类来对需要高亮的效果举行处置。

需要高亮的实在是 2 个字段,一个是 title、一个是 body。而 body 我们不需要完整的内容,只需要摘出其中一部分作为搜索效果的摘要即可。这两个功效,辅助类均已经为我们提供了,我们只需要挪用所需的方式就行。

注重到这里我们需要对 titlebody 两个字段举行高亮处置,其基本逻辑实在就是吸收 titlebody 的值作为输入,高亮处置后再输出。回首一下序列化器的序列化字段,实在也是吸收某个字段的值作为输入,对其举行处置,将其转化为可序列化的效果后输出,和我们需要的逻辑很像。然则,django-rest-framework 并没有提供这些对照个性化需求的序列化字段,因此接下来我们接触 drf 的一点高级用法——自界说序列化字段。

自界说序列化字段实在异常的简朴,基本流程分两步走:

  1. 从 drf 官方提供的序列化字段中找一个数据类型最为靠近的作为父类。
  2. 重写 to_representation 方式,加入自己的序列化逻辑。

以我们的需求为例。由于 titlebody 均为字符型,因此选择父类序列化字段为 CharField,界说一个 HighlightedCharField 字段如下:

from .utils import Highlighter

class HighlightedCharField(CharField):
    def to_representation(self, value):
        value = super().to_representation(value)
        request = self.context["request"]
        query = request.query_params["text"]
        highlighter = Highlighter(query)
        return highlighter.highlight(value)

django-rest-framework 通过挪用序列化字段的 to_representation 方式对输入的值举行序列化,这个方式吸收的第一个参数就是需要序列化的值。在我们自界说的逻辑中,首先挪用父类 CharFieldto_representation 方式,父类序列化的逻辑是将任何输入的值都转为字符串;接着我们从 context 属性中取得 request 工具,这个工具就是视图中的 HTTP 请求工具,然则由于 django 中 request 工具无法像 flask 那样从全局获取,因此 drf 在视图中将其保留在了序列化器和序列化字段的 context 属性中以便在视图外接见;获取 request 工具的目的是希望获取查询的要害字,query_params 属性是一个类字典工具,用于纪录来自 URL 的查询参数,例如我们之前测试查询功效时挪用的 URL 为 /api/search/?text=markdown,以是 query_params 保留了 URL 中的查询参数,将其封装为一个类字段工具 {"text": "markdown"},这里 text 的值就是查询的要害字,我们将它传给 Highlighter 辅助类,然后挪用 highlight 方式将需要序列化的值举行进一步的高亮处置。

序列化字段界说好后,我们就可以在序列化器中用它了:

class PostHaystackSerializer(HaystackSerializerMixin, PostListSerializer):
    title = HighlightedCharField()
    summary = HighlightedCharField(source="body")

    class Meta(PostListSerializer.Meta):
        search_fields = ["text"]
        fields = [
            "id",
            "title",
            "summary",
            "created_time",
            "excerpt",
            "category",
            "author",
            "views",
        ]

title 字段原本使用默认的 CharField 举行序列化,这里我们重新指定为自界说的 HighlightedCharField,这样序列化后的值就是高亮的花样。

summary 是我们新增的字段,注重我们序列化的工具是文章 Post,但这个工具是没有 summary 这个属性的,然则 summary 实在是对属性 body 序列化后的效果,因此我们通过指定序列化化字段的 source 参数,指定值的泉源。

最后别忘了在 fields 中声名所有序列化的字段,主要是把新增的 summary 加进去。

来看看改善后的搜索效果:

欧博开户:第 11 篇:基于 drf-haystack 的文章搜索接口 第1张

注重考察返回的 title 和 summary,我们搜索的要害词是 markdown,可以看到所有 markdown 要害字都被包裹了一个 span 标签,而且设置了 class 属性为 highlighted,只要设置好 css 样式,页面所有的 markdown 要害词就会显示差别的颜色,从而实现搜索要害词高亮的效果了。

固然,我们现在并没有现实用到这个特征,下一部教程我们将使用 Vue 来开发博客,到时候挪用搜索接口拿到搜索效果后就会现实用到了。

欧博开户:第 11 篇:基于 drf-haystack 的文章搜索接口 第2张

关注民众号加入交流群

,

欧博allbet注册

欢迎进入欧博allbet注册(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。

版权声明

本文仅代表作者观点,
不代表本站Allbet的立场。
本文系作者授权发表,未经许可,不得转载。

评论