Тема: І ще один weirdo в django-oscar
В oscar використовується наступна модель бази даних для товарів:
Product(model)
pass
ProductClass(model)
pass
ProductAttribute(model)
foreign_key to ProductClass
product = foreign_key to product
ProductAttributeValue(model)
attribute = foreign_key to ProductAttribute
І для покращення швидкодії все індексується в django-haystack.
Так виглядає цей індекс:
class ProductIndex(indexes.SearchIndex, indexes.Indexable):
... other fields here ...
attributes = indexes.MultiValueField()
attribute_codes = indexes.MultiValueField()
attribute_values = indexes.MultiValueField()
А так ми запихаєм туди значення:
def prepare_attributes(self, obj): # тут тільки назви атрибутів
return [attribute.name for attribute in obj.attributes.all()]
def prepare_attribute_codes(self, obj): # тут їхні коди
return [attribute.code for attribute in obj.attributes.all()]
def prepare_attribute_values(self, obj): # !!!!!!!!!! А тут вже всі значення !!!!!!!!!!
return [val.value for val in obj.attribute_values.all()]
І от тут саме криється проблема! Напр. в нас є 3 продукти з 2 атрибутами: висота і ширина.
1. Foo висота=100 ширина=200
2. Bar висота=200 ширина=100
3. Rab висота=150 ширина 120
І на сайті в мене є потреба зробити пошук товарів за висотою в проміжку від 100 до 120. Потрапити сюди має тільки товар 1 Foo. Але! Приблизно отак ми фільтруємо по індексу:
SearchQuerySet().filter(attribute_values__in=[100, 101, 102 ... 120])
Що в нас в результаті? В нас пошук віддасть товари 1 Foo, 2 Bar і 3 Rab !!!!!!!!!!!
Чому? Тому що, дані зберігаються в списку:
def prepare_attribute_values(self, obj): # !!!!!!!!!! А тут вже всі значення !!!!!!!!!!
return [val.value for val in obj.attribute_values.all()]
# [100, 200] - результат для першого товару
# [200, 100] - результат для другого товару
# [150, 120] - результат для третього товару
Так, я додавав в запит:
SearchQuerySet().filter(attribute_codes='height', attribute_values__in=[100, 101, 102 ... 120])
Але воно ж не поможе! Оскільки, 'height' так само буде в списку від prepare_attribute_codes.
І я також пробував зберегти значення в словник:
def prepare_attribute_values(self, obj):
return {val.attribute.code: val.value for val in obj.attribute_values.all()}
Але це викликає помилку при оновленні індексу.
Хоча б зрозуміли про що я ?
Баг в django-oscar? Чи як можу обійти?