employees trigram search for back-office

This commit is contained in:
Kuroshini 2020-01-15 20:49:33 +03:00
parent 7a7d7a70b0
commit 4b45cab976
6 changed files with 76 additions and 1 deletions

View File

@ -1,6 +1,8 @@
"""Establishment app filters."""
from django.core.validators import EMPTY_VALUES
from django_filters import rest_framework as filters
from rest_framework.serializers import ValidationError
from django.utils.translation import ugettext_lazy as _
from establishment import models
@ -79,3 +81,12 @@ class EmployeeBackFilter(filters.FilterSet):
if value not in EMPTY_VALUES:
return queryset.search_by_name_or_last_name(value)
return queryset
class EmployeeBackSearchFilter(EmployeeBackFilter):
def search_by_name_or_last_name(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

View File

@ -0,0 +1,16 @@
# Generated by Django 2.2.7 on 2020-01-15 17:02
from django.db import migrations
from django.contrib.postgres.operations import TrigramExtension, BtreeGinExtension
class Migration(migrations.Migration):
dependencies = [
('establishment', '0071_auto_20200110_1055'),
]
operations = [
TrigramExtension(),
BtreeGinExtension(),
]

View File

@ -0,0 +1,22 @@
# Generated by Django 2.2.7 on 2020-01-15 17:10
import django.contrib.postgres.indexes
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('establishment', '0072_auto_20200115_1702'),
]
operations = [
migrations.AddIndex(
model_name='employee',
index=django.contrib.postgres.indexes.GinIndex(fields=['name'], name='establishme_name_39fda6_gin'),
),
migrations.AddIndex(
model_name='employee',
index=django.contrib.postgres.indexes.GinIndex(fields=['last_name'], name='establishme_last_na_3c53de_gin'),
),
]

View File

@ -11,6 +11,8 @@ 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.indexes import GinIndex
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
@ -977,6 +979,13 @@ class EmployeeQuerySet(models.QuerySet):
]
return self.filter(reduce(lambda x, y: x | y, [models.Q(**i) for i in filters]))
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')
def search_by_name_or_last_name(self, value):
"""Search by name or last_name."""
return self._generic_search(value, ['name', 'last_name'])
@ -987,6 +996,9 @@ class EmployeeQuerySet(models.QuerySet):
queryset=EstablishmentEmployee.objects.actual()
)).all().distinct()
def with_extended_related(self):
return self.prefetch_related('establishments')
class Employee(BaseAttributes):
"""Employee model."""
@ -1030,6 +1042,10 @@ class Employee(BaseAttributes):
verbose_name = _('Employee')
verbose_name_plural = _('Employees')
indexes = [
GinIndex(fields=('name',)),
GinIndex(fields=('last_name',))
]
class EstablishmentScheduleQuerySet(models.QuerySet):

View File

@ -45,6 +45,7 @@ urlpatterns = [
path('<int:establishment_id>/employees/', views.EstablishmentEmployeeListView.as_view(),
name='establishment-employees'),
path('employees/', views.EmployeeListCreateView.as_view(), name='employees'),
path('employees/search/', views.EmployeesListSearchViews.as_view(), name='employees-search'),
path('employees/<int:pk>/', views.EmployeeRUDView.as_view(), name='employees-rud'),
path('<int:establishment_id>/employee/<int:employee_id>/position/<int:position_id>',
views.EstablishmentEmployeeCreateView.as_view(),

View File

@ -2,7 +2,7 @@
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import generics, permissions, status
from rest_framework import generics, permissions, status, filters as rest_filters
from account.models import User
from establishment import filters, models, serializers
@ -174,6 +174,15 @@ class EmployeeListCreateView(generics.ListCreateAPIView):
queryset = models.Employee.objects.all()
class EmployeesListSearchViews(generics.ListAPIView):
"""Employee search view"""
pagination_class = None
permission_classes = (permissions.AllowAny,)
queryset = models.Employee.objects.all()
filter_class = filters.EmployeeBackSearchFilter
serializer_class = serializers.EmployeeBackSerializers
class EstablishmentEmployeeListView(generics.ListCreateAPIView):
"""Establishment emplyoees list view."""
permission_classes = (permissions.AllowAny,)