在Django/PostgreSQL搜索结果页面上突出显示搜索词

10

如何在Django 1.11中使用PostgreSQL全文搜索创建一个搜索结果页面,使得搜索的词语被高亮显示?


让我确认一下你的要求。基本上,就像在这个屏幕上一样,如果你在Chrome中按下cmd/ctrl + f并搜索“ask”,会得到许多黄色高亮显示的内容。你想要相同的外观,但你希望它是一个列表视图? - raiderrobert
正确。本文讨论的是:https://alistapart.com/article/searchhighlight - jmn
3个回答

17

尽管Django不支持来自PostgreSQL的ts_headline功能,但您可以将其手动应用于QuerySet上作为一个Function进行注释:


我们需要额外的函数来操作Django ORM。这是一个使用ts_headline的示例代码。[此示例函数的原始来源链接在这里]

ts_headline函数示例:

from django.db import models
from django.contrib.postgres.search import Value, Func


class Headline(Func):
    function = 'ts_headline'

    def __init__(self, field, query, config=None, options=None, **extra):
        expressions = [field, query]
        if config:
            expressions.insert(0, Value(config))
        if options:
            expressions.append(Value(options))
        extra.setdefault('output_field', models.TextField())
        super().__init__(*expressions, **extra)

使用上述函数,您可以在QuerySet上使用它进行注释。

示例模型定义

class Video(Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(max_length=128, verbose_name="Title")

获取模型标题高亮搜索结果的步骤

  1. 筛选并获取需要进行注释的 QuerySet
  2. 使用 Headline 函数进行注释
  3. 获取文档的值

对象筛选

Video.objects.filter(filter_query)

filter_query是在标题上的Q()查询 filter_query = Q(title__contains=term)


使用标题数据进行注释

Video.objects.filter(filter_query).annotate(title_highlight=Headline(F('title'), text_search_query))

ts_headline 直接从文档中获取输入而不是从 ts_vector 中获取,所以我们必须传递关于它应该访问哪个字段以及应该在其中执行什么 SearchQuery 的信息。

text_Search_query 是具有与 filter_query 相同输入的 SearchQuery 对象 text_search_query = SearchQuery(term)

现在在注释之后,这个 queryset 将在所有对象中包含一个名为 title_highlight 的额外字段,其中将包含您想要的结果,如:

these <b>loans</b> not being repaired


从注释字段中获取值

使用 QuerySet 上的 values_list 可以获取这些注释字段的值。

最终代码:

Video.objects.filter(filter_query).annotate(title_highlight=Headline(F('title'), text_search_query)).values_from('title','title_highlight')

很好。如果你想要整个字符串,而不仅仅是提取部分,请使用 Headline(F('title'), text_search_query, options='HighlightAll=TRUE') - Flimm
很棒的内容。真的帮了我很多。谢谢。 - Sarath Chandran K
这个答案已经过时了。从Django 3.1开始,有一个SearchHeadline类,可以通过from django.contrib.postgres.search import SearchHeadline导入。 - xax

0
问题涉及Django 1.11。随着Django 3.1的推出,情况已经发生了变化,现在有一个名为SearchHeadline的类。
我在Stack Overflow上没有看到太多关于这个的代码,所以请参考以下内容:
假设models.py包含一个Article模型。它有两个TextField('headline'/'content')和一个用于内容的SearchVectorField:
``` from django.contrib.postgres.search import SearchVector, SearchVectorField, SearchHeadline from django.db.models import F, Q
class Article(models.Model): headline = models.TextField() content = models.TextField() content_vector = SearchVectorField(null=True) ```
在您的控制台/终端中,以下代码将起作用:
``` query = "book"
Article.objects .annotate(v_head=SearchHeadline(F("content"), query)) .filter(content_vector=query) ```
以上有两个部分 - 使用SearchHeadline注释v_head '列',然后针对“book”查询本身进行过滤。
假设文本是“Lorem ipsum book lorem ipsum”,输出将是:
``` Lorem ipsum book lorem ipsum。 ```

你可以在 Github 上看到 其他类似的代码


0
在Django 3.1中,现在有一个SearchHeadline类,使得这个任务变得更加简单。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接