Django Rest Framework. Подскажите какую-нибудь библиотеку для умного поиска

Хочу сделать умный фильтр по кверисету по одному полю, способный найти объекты, даже если пользователем была допущена ошибка или если пользователь забыл переключить раскладку клавиатуры, как это происходит в поисковиках.

Пока что накидал такой метод в фильтрах

from django.contrib.postgres.search import SearchQuery, SearchVector
from django_filters import rest_framework as filters


class AddressFilter(filters.FilterSet):
    name = filters.CharFilter(method='filter_name_smart')

    class Meta:
        model = Address
        fields = ['name']

    def filter_name_smart(self, queryset, name, value):
        value_list = value.split(' ')
        search_vector = SearchVector(name)
        query_list = [SearchQuery(value) for value in value_list]
        while len(query_list) > 1:
            query1 = query_list.pop()
            query2 = query_list.pop()
            query_list.append(query1 & query2)
        search_query = query_list[0]
        return queryset.annotate(search=search_vector).filter(search=search_query)

Он может искать по отдельным словам в названиях

Например запрос: localhost/api/addresses/?name=the cafe

Выдает объекты с названиями: The Buddy cafe, Cafe Imperial, Corner Cafe и прочие похожие.

Данное поведение меня устраивает, но хотелось бы большего, чтобы я мог допустить ошибку или забыл переключить раскладку, например:

?name=the cfe

?name=еру сфау

Есть ли либы, которые помогли бы реализовать такую фичу?

В общем, раскладку мне переключать не нужно было по ТЗ

А по поиску с ошибками нашел очень интересный вариант TrigramExtension

https://docs.djangoproject.com/en/2.2/ref/contrib/postgres/operations/#trigramextension

Ищет вполне сносно. Интересно устанавливается через добавление django.contrib.postgres в INSTALLED_APPS и через миграции

from django.contrib.postgres.operations import TrigramExtension, UnaccentExtension
from django.db import migrations


class Migration(migrations.Migration):

    operations = [
        TrigramExtension(),
    ]

И реализуется в одну строчку

def filter_name_smart(self, queryset, name, value):
    return queryset.filter(name__trigram_similar=value)

Или даже без метода

class AddressFilter(filters.FilterSet):
    name = filters.CharFilter(lookup_expr='trigram_similar')
Вернуться на верх