JSON 字段上的 Django 全文搜索

Pep*_*zza 3 django postgresql json full-text-search

我正在尝试为Django 1.10实现新添加的 Fulltext-search Postgres 支持。

我尝试搜索的字段之一是 JSON 字段:

from django.contrib.postgres.fields import JSONField
class Product():
        attributes = JSONField(...)
Run Code Online (Sandbox Code Playgroud)

如果我尝试使用SearchVector 进行以下搜索

Product.objects.annotate(
    search=SearchVector('attributes'),
).filter(search=keyword)
Run Code Online (Sandbox Code Playgroud)

将提高:

django.db.utils.DataError: invalid input syntax for type json
LINE 1: ...ol1, to_tsvector(COALESCE("product"."attributes", '')) AS "s...
                                                         ^
DETAIL:  The input string ended unexpectedly.
CONTEXT:  JSON data, line 1:
Run Code Online (Sandbox Code Playgroud)

这是有道理的,像这样的原始 SQL 查询需要是

select to_tsvector(attributes::text) from product;
Run Code Online (Sandbox Code Playgroud)

但是如何在 Django 语法中实现该字段转换?

Pao*_*rre 7

正如@e4c5 报道的那样,自Django 1.10(与您使用的版本相同)以来就有Cast功能。

因此,如果您要将 JSON 字段作为文本进行搜索,则必须将其转换为文本:

from django.contrib.postgres.search import SearchVector
from django.db.models import TextField
from django.db.models.functions import Cast

Product.objects.annotate(
    search=SearchVector(Cast('attributes', TextField())),
).filter(search=keyword)
Run Code Online (Sandbox Code Playgroud)

您还可以在 SearchVector 中仅使用 JSON 字段的特定部分:

from django.contrib.postgres.search import SearchVector
from django.contrib.postgres.fields.jsonb import KeyTextTransform

Product.objects.annotate(
    search=SearchVector(KeyTextTransform('key1', 'attributes')),
).filter(search=keyword)
Run Code Online (Sandbox Code Playgroud)

PostgreSQL 10 添加了对 JSON 和 JSONB 的全文搜索支持

  • 实际上,官方 Django 文档邀请大家尽可能避免使用 RawSQL。动机不仅与可移植性和 DRY 有关,还与安全性有关。我邀请您阅读:https://docs.djangoproject.com/en/2.0/ref/models/expressions/#django.db.models.expressions.RawSQL (2认同)