选择字段上的 Django SearchVector
Django SearchVector on choices field
如果我有一个简单的 Django 模型,例如:
from model_utils import Choices
class Art(models.Model):
CATEGORIES = Choices(
(1, 'DIGITAL_ART', 'Digital Art'),
(2, 'MULTIMEDIA', 'Multimedia'),
)
title = models.TextField()
category = models.PositiveSmallIntegerField(
db_index=True, choices=CATEGORIES, blank=True, null=True
)
如何在 postgres 中使用 SearchVector
以允许在标题和类别字段上进行搜索?例如。所以 "Some Book Digital Art" 将查询标题和类别字段。
问题是 database-level 选项字段存储为整数,而不是文本。
有没有一种方法可以在创建搜索向量时将整数映射到相应的文本值?
我能想到的第一个解决方案是使用 Conditional Expression to add the category text into the SearchVector:
from django.db.models import Case, CharField, Value, When
from django.contrib.postgres.search import SearchVector
Art.objects.annotate(
category_text=Case(
When(category=1, then=Value('Digital Art')),
When(category=2, then=Value('Multimedia')),
default=Value(''),
output_field=CharField()
),
search=SearchVector('title') + SearchVector('category_text')
).filter(
search='Some Book Digital Art'
).values_list('title', flat=True)
此查询的结果类似于:
<QuerySet ['Some Book']>
并且为 PostgreSQL 生成的 SQL 像这样:
SELECT "arts_art"."title"
FROM "arts_art"
WHERE (
to_tsvector(COALESCE("arts_art"."title", '')) ||
to_tsvector(COALESCE(
CASE
WHEN ("arts_art"."category" = 1) THEN 'Digital Art'
WHEN ("arts_art"."category" = 2) THEN 'Multimedia'
ELSE ''
END, '')
)
) @@ (plainto_tsquery('Some Book Digital Art')) = TRUE
更新
您可以从您的选择列表中自动构建查询:
from django.db.models import Case, CharField, Value, When
from django.contrib.postgres.search import SearchVector
CATEGORIES = (
(1, 'Digital Art'),
(2, 'Multimedia'),
)
Art.objects.annotate(
category_text=Case(
*[When(category=c, then=Value(v)) for c, v in CATEGORIES],
default=Value(''),
output_field=CharField()
),
search=SearchVector('title') + SearchVector('category_text')
).filter(
search='Some Book Digital Art'
).values_list('title', flat=True)
如果我有一个简单的 Django 模型,例如:
from model_utils import Choices
class Art(models.Model):
CATEGORIES = Choices(
(1, 'DIGITAL_ART', 'Digital Art'),
(2, 'MULTIMEDIA', 'Multimedia'),
)
title = models.TextField()
category = models.PositiveSmallIntegerField(
db_index=True, choices=CATEGORIES, blank=True, null=True
)
如何在 postgres 中使用 SearchVector
以允许在标题和类别字段上进行搜索?例如。所以 "Some Book Digital Art" 将查询标题和类别字段。
问题是 database-level 选项字段存储为整数,而不是文本。
有没有一种方法可以在创建搜索向量时将整数映射到相应的文本值?
我能想到的第一个解决方案是使用 Conditional Expression to add the category text into the SearchVector:
from django.db.models import Case, CharField, Value, When
from django.contrib.postgres.search import SearchVector
Art.objects.annotate(
category_text=Case(
When(category=1, then=Value('Digital Art')),
When(category=2, then=Value('Multimedia')),
default=Value(''),
output_field=CharField()
),
search=SearchVector('title') + SearchVector('category_text')
).filter(
search='Some Book Digital Art'
).values_list('title', flat=True)
此查询的结果类似于:
<QuerySet ['Some Book']>
并且为 PostgreSQL 生成的 SQL 像这样:
SELECT "arts_art"."title"
FROM "arts_art"
WHERE (
to_tsvector(COALESCE("arts_art"."title", '')) ||
to_tsvector(COALESCE(
CASE
WHEN ("arts_art"."category" = 1) THEN 'Digital Art'
WHEN ("arts_art"."category" = 2) THEN 'Multimedia'
ELSE ''
END, '')
)
) @@ (plainto_tsquery('Some Book Digital Art')) = TRUE
更新
您可以从您的选择列表中自动构建查询:
from django.db.models import Case, CharField, Value, When
from django.contrib.postgres.search import SearchVector
CATEGORIES = (
(1, 'Digital Art'),
(2, 'Multimedia'),
)
Art.objects.annotate(
category_text=Case(
*[When(category=c, then=Value(v)) for c, v in CATEGORIES],
default=Value(''),
output_field=CharField()
),
search=SearchVector('title') + SearchVector('category_text')
).filter(
search='Some Book Digital Art'
).values_list('title', flat=True)