Как довести до ума полнотекстовый поиск в Djnago + PostgreSQL?

Есть полнотекстовый поиск реализованный с помощью "django.contrib.postgres". Обрабатывается во Views таким образом:
class search(ListView):
    model = Product
    paginate_by = 14
    template_name = 'catalog/product_list.html'
    def get_queryset(self):   
        stop_words = ~SearchQuery(['и', 'при', 'а', 'для', 'в', 'на', 'из', 'которые', 'дешовый', 'специальные', 'недорогие', 'по', 'у', 'за'])
        queryset = super(search, self).get_queryset()
        q = self.request.GET.get("q")
        if q: 
            return queryset.annotate(search=SearchVector('brand__name', 'name', 'category__name', 'categorysub__name')).order_by('price').filter(search=q)  
            return queryset.annotate(search=SearchVector('brand__name', 'name', 'category__name', 'categorysub__name')).order_by('price').filter(search=stop_words))
        elif not q:
            return queryset.order_by('price')


Как сделать, чтобы он искал, если писать название не полностью и если искать по одному полю несколько записей.
Например нужно писать полностью "кабельный", а просто "кабель" уже не ищет или если искать сразу два бренда, то тоже не ищет , только если указать один в запросе.

Сама модель по которой происходит поиск:
class Product(models.Model):
    category = models.ForeignKey(Category, related_name='products', verbose_name="Категория")
    categorysub = models.ForeignKey(SubCategory, null=True, blank=True, verbose_name="Подкатегория")
    name = models.CharField(max_length=100, db_index=True, verbose_name="Название")
    slug = models.SlugField(max_length=100, db_index=True, verbose_name="Псевдоним")
    image = models.ImageField(upload_to='static/products/%Y/%m/%d/', blank=True, verbose_name="Изображение товара")
    description = models.TextField(blank=True, verbose_name="Описание")
    brand = models.ForeignKey(Brand, related_name='products', null=True, verbose_name="Бренд")
    price = models.DecimalField(max_digits=10, decimal_places=0, verbose_name="Цена")
    stock = models.PositiveIntegerField(verbose_name="На складе") 
    available = models.BooleanField(default=True, verbose_name="Доступен")
    created = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания")
    updated = models.DateTimeField(auto_now=True, verbose_name="Дата обновления") 

    class Meta:
        verbose_name = 'Продукт'
        verbose_name_plural = 'Продукты'
        ordering = ['name']
        index_together = [
            ['id', 'slug']
        ]

    def __str__(self):
        return self.name
  • Вопрос задан
  • 2000 просмотров
Решения вопроса 1
@Tryggvi Автор вопроса
Раз никто не отвечает, то я отвечу сам.
В PostgreSQL активируем расширение "pg_trgm":
CREATE EXTENSION pg_trgm;
Потом во Views импортируем:
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector, TrigramSimilarity


И в обработке запроса используем данную логику:

vector = SearchVector('categorysub__name', 'brand__name', 'category__name', 'name', raw=True, fields=('name'))
vector_trgm = TrigramSimilarity('categorysub__name', q, raw=True, fields=('name')) + TrigramSimilarity('brand__name', q, raw=True, fields=('name')) + TrigramSimilarity('category__name', q, raw=True, fields=('name')) + TrigramSimilarity('name', q, raw=True, fields=('name'))
return queryset.annotate(search=vector).order_by('price').filter(search=q) or queryset.annotate(similarity=vector_trgm).filter(similarity__gt=0.2).order_by('price')


Таким образом мы получаем полнотекстовый поиск, который так же будет корректно работать, если пользователь опечатался.

Если использовать TrigramSimilarity без SearchVector, то результат поиска будет не всегда правдивым.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@DrNemez
Python Junior Dev
А в SearchVector нет аргументов raw & fields где они используются?
И будет вот эта ошибка __init__() got an unexpected keyword argument 'raw'

Я немного переделал под 2021год). И свои требования и заработало!
Очень Вам благодарен, что вы написали решение на этот вопрос.
Спасибо.

И Вопрос где вы инфу нашли? К этому вопросу. В офф доке это есть но не в комбинации.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы