diff --git a/shop/models/product.py b/shop/models/product.py index 8f80657b3..466ec1fe6 100644 --- a/shop/models/product.py +++ b/shop/models/product.py @@ -5,6 +5,7 @@ from functools import reduce import operator from cms import __version__ as CMS_VERSION + from django.core import checks from django.db import models from django.db.models.aggregates import Sum diff --git a/shop/search/documents.py b/shop/search/documents.py index d833cd582..68fd0f07b 100644 --- a/shop/search/documents.py +++ b/shop/search/documents.py @@ -2,8 +2,9 @@ from __future__ import unicode_literals from django.template.loader import select_template +from django.utils import translation -from django_elasticsearch_dsl import fields, Document +from django_elasticsearch_dsl import fields, Document, Index from elasticsearch_dsl import analyzer from shop.models.product import ProductModel @@ -17,7 +18,7 @@ ) -class ProductDocument(Document): +class _ProductDocument(Document): product_code = fields.KeywordField( multi=True, boost=5, @@ -57,7 +58,6 @@ def prepare_body(self, instance): Create a textual representation of the product's instance to be used by Elasticsearch for creating a full text search index. """ - print(f"------------ {instance.id}: {instance.product_model}") app_label = instance._meta.app_label.lower() params = [ (app_label, instance.product_model), @@ -66,5 +66,26 @@ def prepare_body(self, instance): ] template = select_template(['{0}/search/indexes/{1}.txt'.format(*p) for p in params]) body = template.render({'product': instance}) - print(body) return body + + def update(self, thing, refresh=None, action='index', parallel=False, **kwargs): + with translation.override(self._language): + super().update(thing, refresh=None, action='index', parallel=False, **kwargs) + + +class ProductDocument: + def __new__(cls, language=None, settings=None, analyzer=None): + if language: + index_name = 'products-{}'.format(language.lower()) + doc_name = 'ProductDocument{}'.format(language.title()) + else: + index_name = 'products' + doc_name = 'ProductDocument' + products_index = Index(index_name) + if settings: + products_index.settings(**settings) + if analyzer: + products_index.analyzer(analyzer) + doc_class = type(doc_name, (_ProductDocument,), {'_language': language}) + products_index.document(doc_class) + return doc_class diff --git a/shop/search/mixins.py b/shop/search/mixins.py index ec357e2d1..0771dbf77 100644 --- a/shop/search/mixins.py +++ b/shop/search/mixins.py @@ -1,19 +1,23 @@ -from shop.search.documents import ProductDocument +from django.utils.translation import get_language_from_request + +from django_elasticsearch_dsl.registries import registry + +from shop.models.product import ProductModel class SearchViewMixin: - def get_queryset(self): - query = self.request.GET.get('q') - if query: - search = ProductDocument.search().source(excludes=['body']) - search = search.query('multi_match', query=query, fields=self.search_fields, type='bool_prefix') - queryset = search.to_queryset() - else: - queryset = super().get_queryset() - return queryset + def get_document(self, language): + documents = registry.get_documents([ProductModel]) + try: + return next(doc for doc in documents if doc._language == language) + except StopIteration: + return next(doc for doc in documents if doc._language is None) class ProductSearchViewMixin(SearchViewMixin): + """ + Mixin class to be added to the ProductListView so that autocompletion works. + """ search_fields = ['product_name', 'product_code'] def get_renderer_context(self): @@ -22,10 +26,34 @@ def get_renderer_context(self): renderer_context['search_autocomplete'] = True return renderer_context + def get_queryset(self): + query = self.request.GET.get('q') + if query: + language = get_language_from_request(self.request) + document = self.get_document(language) + search = document.search().source(excludes=['body']) + search = search.query('multi_match', query=query, fields=self.search_fields, type='bool_prefix') + queryset = search.to_queryset() + else: + queryset = super().get_queryset() + return queryset + class CatalogSearchViewMixin(SearchViewMixin): + """ + Mixin class to be added to the ProductListView in order to create a full-text search. + """ search_fields = ['product_name', 'product_code', 'body'] def get_serializer(self, *args, **kwargs): kwargs.setdefault('label', 'search') return super().get_serializer(*args, **kwargs) + + def get_queryset(self): + language = get_language_from_request(self.request) + document = self.get_document(language) + query = self.request.GET.get('q') + search = document.search().source(excludes=['body']) + if query: + search = search.query('multi_match', query=query, fields=self.search_fields) + return search.to_queryset()