news trigram search

This commit is contained in:
Kuroshini 2020-01-21 18:58:26 +03:00
parent de50d6491f
commit 6a36bb5a13
2 changed files with 55 additions and 2 deletions

View File

@ -1,6 +1,8 @@
"""Filters from application News"""
from django_filters import rest_framework as filters
from django.core.validators import EMPTY_VALUES
from django.utils.translation import gettext_lazy as _
from django_filters import rest_framework as filters
from rest_framework.serializers import ValidationError
from news import models
@ -29,6 +31,7 @@ class NewsListFilterSet(filters.FilterSet):
(SORT_BY_START_CHOICE, "start"),
)
sort_by = filters.ChoiceFilter(method='sort_by_field', choices=SORT_BY_CHOICES)
search = filters.CharFilter(method='search_news')
class Meta:
"""Meta class"""
@ -41,8 +44,16 @@ class NewsListFilterSet(filters.FilterSet):
'tag_value__in',
'state',
'sort_by',
'search',
)
def search_news(self, queryset, name, value):
if value not in EMPTY_VALUES:
if len(value) < 3:
raise ValidationError({'detail': _('Type at least 3 characters to search please.')})
return queryset.trigram_search(value)
return queryset
def in_tags(self, queryset, name, value):
tags = value.split('__')
return queryset.filter(tags__value__in=tags)

View File

@ -6,7 +6,9 @@ from django.contrib.contenttypes import fields as generic
from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.fields import HStoreField
from django.db import models
from django.db.models import Case, When
from django.db.models import Case, When, Q, F
from django.db.models.functions import Cast
from django.contrib.postgres.search import TrigramSimilarity
from django.urls.exceptions import NoReverseMatch
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
@ -144,6 +146,46 @@ class NewsQuerySet(TranslationQuerysetMixin):
def by_locale(self, locale):
return self.filter(title__icontains=locale)
def trigram_search(self, search_value: str):
"""Search with mistakes by name or last name."""
return self.annotate(
description_str=Cast('description', models.TextField()),
title_str=Cast('title', models.TextField()),
subtitle_str=Cast('subtitle', models.TextField()),
search_contains_match=Case(
models.When(Q(description_str__icontains=search_value) | Q(title_str__icontains=search_value) | Q(
subtitle_str__icontains=search_value), then=100),
default=0,
output_field=models.FloatField(),
),
description_similarity=models.Case(
models.When(
Q(description__isnull=False),
then=TrigramSimilarity('description_str', search_value.lower()),
),
default=0,
output_field=models.FloatField()
),
title_similarity=models.Case(
models.When(
Q(title__isnull=False),
then=TrigramSimilarity('title_str', search_value.lower()),
),
default=0,
output_field=models.FloatField()
),
subtitle_similarity=models.Case(
models.When(
Q(subtitle__isnull=False),
then=TrigramSimilarity('subtitle_str', search_value.lower()),
),
default=0,
output_field=models.FloatField()
),
relevance=(F('search_contains_match') + F('description_similarity') + F('title_similarity') + F(
'subtitle_similarity'))
).filter(relevance__gte=0.3).order_by('-relevance')
class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin,
FavoritesMixin):