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

问题描述 投票:0回答:4

如何使用 PostgreSQL 全文搜索在 Django 1.11 中创建搜索结果页面,其中搜索的术语会突出显示?

django postgresql django-rest-framework full-text-search
4个回答
17
投票

即使 Django 不支持 postgresql 的 ts_headline 功能,您也可以手动将其作为

Function
应用于
QuerySet
上进行注释:


我们需要额外的功能来使用 django ORM 进行操作。这是 ts_headline 的示例。 [此示例函数的原始源链接为here]

标题功能示例:

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)

使用上面的函数,您可以在查询集上使用它来注释

模型定义示例

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. 使用标题功能进行注释
  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 是 SearchQuery 对象,其输入与 filter_query 相同 text_search_query = SearchQuery(术语)

现在在注释之后,此查询集在所有对象中包含一个名为 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')

0
投票

在 Django 3.1 中,现在有一个

SearchHeadline
类,这使得这个任务变得更加简单。


0
投票

问题询问 Django 1.11。事情发生了变化,因为 Django 3.1 中有一个

SearchHeadline
类。

我在 Stack Overflow 上没有注意到太多这方面的代码,所以请考虑以下几点:

  1. 假设 models.py 包含一个 Article 模型。它有两个

    TextField
    (“标题”/“内容”)和一个
    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)
    
  2. 在您的控制台/终端中,以下代码将起作用:

    query = "book"
    
    Article.objects
    .annotate(v_head=SearchHeadline(F("content"), query))
    .filter(content_vector=query)
    
  3. 上面有两个部分 - 使用

    SearchHeadline
    注释 v_head 'column',然后过滤器本身针对“book”的查询。

  4. 假设文本是“Lorem ipsum book lorem ipsum”,输出将是:

    Lorem ipsum lorem ipsum。

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


0
投票

如果您不反对使用一点 JavaScript,您可以利用 CSS 自定义突出显示 API 在客户端完成此操作。现代浏览器提供了一种通过创建

Range
并将其添加到
Highlight
来突出显示搜索词的本机方法。

const contentNode = document.getElementById("content");

// Create ranges where you want to highlight text
const range1 = new Range();
range1.setStart(contentNode, 10);
range1.setEnd(contentNode, 20);

const range2 = new Range();
range2.setStart(contentNode, 40);
range2.setEnd(contentNode, 60);

// Create a Highlight with these ranges
const highlight = new Highlight(range1, range2);

// Add this highlight to the HighlightRegistry
CSS.highlights.set("search-result", user1Highlight);

您现在可以在 CSS 中设置突出显示的样式:

::highlight(search-result) {
    background-color: yellow;
    color: black;
}

术语的实际搜索可以在服务器端或客户端完成。

此方法的优点是它提供了一个干净的 DOM,例如,当您必须突出显示

contentEditable
元素中的文本时,这非常有用。

© www.soinside.com 2019 - 2024. All rights reserved.