From 8b4a6b0b740270f98eaf7e036aa442891c12d4a9 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Fri, 17 Jan 2020 16:13:27 +0300 Subject: [PATCH] fix employees search --- apps/establishment/models.py | 38 +++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index d7cc9e7e..5f8ec73d 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -11,12 +11,12 @@ from django.contrib.gis.db.models.functions import Distance from django.contrib.gis.geos import Point from django.contrib.gis.measure import Distance as DistanceMeasure from django.contrib.postgres.fields import ArrayField -from django.contrib.postgres.search import TrigramDistance +from django.contrib.postgres.search import TrigramDistance, TrigramSimilarity from django.contrib.postgres.indexes import GinIndex from django.core.exceptions import ValidationError from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models -from django.db.models import When, Case, F, ExpressionWrapper, Subquery, Q, Prefetch +from django.db.models import When, Case, F, ExpressionWrapper, Subquery, Q, Prefetch, Sum from django.utils import timezone from django.utils.translation import gettext_lazy as _ from phonenumber_field.modelfields import PhoneNumberField @@ -990,9 +990,37 @@ class EmployeeQuerySet(models.QuerySet): def trigram_search(self, search_value: str): """Search with mistakes by name or last name.""" return self.annotate( - name_distance=TrigramDistance('name', search_value.lower()), - last_name_distance=TrigramDistance('last_name', search_value.lower()), - ).filter(Q(name_distance__lte=0.7) | Q(last_name_distance__lte=0.7)).order_by('name_distance') + search_exact_match=models.Case( + models.When(Q(name__iexact=search_value) | Q(last_name__iexact=search_value), + then=100), + default=0, + output_field=models.FloatField() + ), + search_contains_match=models.Case( + models.When(Q(name__icontains=search_value) | Q(last_name__icontains=search_value), + then=50), + default=0, + output_field=models.FloatField() + ), + search_name_similarity=models.Case( + models.When( + Q(name__isnull=False), + then=TrigramSimilarity('name', search_value.lower()) + ), + default=0, + output_field=models.FloatField() + ), + search_last_name_similarity=models.Case( + models.When( + Q(last_name__isnull=False), + then=TrigramSimilarity('last_name', search_value.lower()) + ), + default=0, + output_field=models.FloatField() + ), + relevance=(F('search_name_similarity') + F('search_exact_match') + + F('search_contains_match') + F('search_last_name_similarity')) + ).filter(relevance__gte=0.3).order_by('-relevance') def search_by_name_or_last_name(self, value): """Search by name or last_name."""