T
T
Tryggvi2018-03-15 23:24:54
PostgreSQL
Tryggvi, 2018-03-15 23:24:54

How to bring full text search to mind in Djnago + PostgreSQL?

There is a full text search implemented using "django.contrib.postgres". Handled in Views like this:

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')

How to make it search if the name is not written in full and if you search for several records in one field.
For example, you need to write completely "cable", but just "cable" is no longer looking for, or if you look for two brands at once, then it does not look either, only if you specify one in the request.
The model itself on which the search is performed:
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

Answer the question

In order to leave comments, you need to log in

2 answer(s)
T
Tryggvi, 2018-03-21
@Tryggvi

Since no one answers, I will answer myself.
In PostgreSQL we activate the "pg_trgm" extension:
Then in Views we import:
And in request processing we use this logic:

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')

Thus, we get a full-text search, which will also work correctly if the user mistyped.
If used TrigramSimilaritywithout , SearchVector,then the search result will not always be true.

R
Ruslan, 2021-04-01
@DrNemez

And in SearchVector there are no raw & fields arguments where are they used?
And there will be this error __init__() got an unexpected keyword argument 'raw' (
I redid it a bit for 2021). And their requirements and earned!
Thank you very much for posting the answer to this question.
Thank you.
And the question is where did you find the info? To this question. In the off dock it is there but not in combination.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question