I
I
Ilya Oskin2017-01-09 01:53:28
Django
Ilya Oskin, 2017-01-09 01:53:28

How to implement faceted filtering in Django?

Hello! Tell me how best to implement faceted filtering of goods in the store.
All product properties that will be filtered are stored in tags that are associated with the product model via ManyToManyField. In the catalog section, only those tags that are associated with products of this category are displayed, the following function is responsible for selecting the necessary tags:

class TagFilter(object):
    def __init__(self, category_slug, prop_name):
        self.name = prop_name
        tags = []
        tag_set = Tag.objects.filter(prop=prop_name, products__in=Product.objects.filter(category=category_slug)).values_list('name', flat=True)
        for t in tag_set:
            if t not in tags:
                tags.append(t)
        self.tags = tags

All that I could do next was to display these tags in the template, and I got up with the implementation of the filtering itself. In addition to filtering by tags, there is also filtering by manufacturers, as well as displaying goods at a decreasing price / increasing price - and I can’t figure out how to implement this.
I read about Haystack and ElasticSearch, but I'm not sure how exactly they should be applied to solve the
Model problem:
@python_2_unicode_compatible
class Tag(models.Model):
    PROPS = (
        ('c', 'цвет'),
        ('e', 'эффект'),
    )
    name = models.CharField(_('Tag name'), max_length=30, unique=True)
    prop = models.CharField(_('Tag property'), max_length=30, choices=PROPS)

    def __str__(self):
        return self.name 
    class Meta:
        verbose_name = 'Тег'
        verbose_name_plural = 'Теги'        

@python_2_unicode_compatible
class Product(models.Model):
    UNITS = (
        ('кг', 'кг.'),
        ('гр', 'гр.'),
        ('шт', 'шт.'),
    )
    name = models.CharField(_('Product name'), max_length=60)
    slug = models.SlugField(_('Unique product slug'), max_length=60, unique=True, null=True)
    category = models.ManyToManyField(Category, related_name='products')
    tag = models.ManyToManyField(Tag, related_name='products', blank=True, null=True)
    manufacturer = models.ForeignKey(Manufacturer, related_name='products', 
                                                    blank=True, null=True, on_delete=models.SET_NULL)
    active = models.BooleanField(_('Enable product?'), default=False)
    price = models.IntegerField(_('Price'))
    price_discounted= models.IntegerField(_('Price with discount'), blank=True, null=True)
    description = models.TextField(_('Product description'), max_length=501, blank=True, null=True)
    brief = models.CharField(_('Brief descr for cat. view'), max_length=60)
    netto = models.PositiveIntegerField(_('Netto mass'))
    preview = models.ImageField(_('Product preview image'), upload_to="images")
    unit = models.CharField(_('Unit'), choices=UNITS, max_length=11)
    stock = models.BooleanField(_('Is in stock?'), default=False)

    def get_preview_price(self):
        return self.price * self.netto

#    def get_absolute_url(self):
#        return reverse('teashop:ProductView', args=[self.slug])    

    def __str__(self):
        return self.name

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

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question