Django SearchVector на поле выбора - PullRequest
       19

Django SearchVector на поле выбора

0 голосов
/ 20 декабря 2018

Если у меня есть простая модель 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
    )

Как я могу использовать SearchVector в postgres для поиска в полях заголовка и категории?Например, «Some Book Digital Art» будет запрашивать поля заголовка и категории.

Проблема в том, что на уровне базы данных поле выбора хранится как целое число, а не как текст.

Есть ли способ, которым я мог бы просто сопоставить целое число с соответствующим значением текста при создании моего вектора поиска?

1 Ответ

0 голосов
/ 21 декабря 2018

Первое решение, о котором я могу подумать, - это использование Условное выражение для добавления текста категории в 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']>

И SQL, сгенерированный для PostgreSQL, выглядит так:

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)
...