Здравствуйте! Подскажите как лучше реализовать фасетную фильтрацию товаров в магазине.
Все свойства товаров, по которым будет осуществляться фильтрация хранятся в тегах, которые связываются с моделью продукта через ManyToManyField. В разделе каталога выводятся только те теги, которые привязаны к продуктам данной категории, за выбор нужных тегов отвечает такая функция:
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
Всё что я дальше смог сделать - это вывести эти теги в шаблон, а с реализацией самой фильтрации встал. Помимо фильтрации по тегам есть ещё фильтрация по производителям, а также вывод товаров по убывающей цене/возрастающей цене - и как реализовать это не могу понять.
Читал про Haystack и ElasticSearch, но не уверен как именно их нужно применить для решения проблемы
Модели:
@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']
]