From 6e387296f826f74f25cf16c6dc266a29627f0600 Mon Sep 17 00:00:00 2001 From: duker Date: Sat, 1 Sep 2018 15:38:12 +0300 Subject: [PATCH] #550 Fork TaggedCategoryContext class --- shopelectro/context.py | 128 +++++++++++++++++++++++++---------- shopelectro/views/catalog.py | 41 ++--------- 2 files changed, 100 insertions(+), 69 deletions(-) diff --git a/shopelectro/context.py b/shopelectro/context.py index 7daf610d..eceb304c 100644 --- a/shopelectro/context.py +++ b/shopelectro/context.py @@ -29,6 +29,18 @@ from pages.models import ModelPage, Page +class SortingOption: + def __init__(self, index=0): + options = settings.CATEGORY_SORTING_OPTIONS[index] + self.label = options['label'] + self.field = options['field'] + self.direction = options['direction'] + + @property + def directed_field(self): + return self.direction + self.field + + @lru_cache(maxsize=64) def merge_products_context(products): images = Image.objects.get_main_images_by_pages( @@ -52,45 +64,58 @@ class ObjectsComposition: super = object() + # TODO - resolve objects good piping def __or__(self, other): self.super = other + return self class AbstractContext(ObjectsComposition): - # TODO - raise not implemented here - # @property - # def request(self): - # raise NotImplemented() + def __init__( + self, + # TODO slug maybe part of url_kwargs + slug='', + url_kwargs: typing.Dict[str, str]=None, + request: http.HttpRequest=None + ): + """ + :param url_kwargs: Came from `urls` module. + :param request: Came from `urls` module + """ + self.slug_ = slug + self.url_kwargs_ = url_kwargs or {} + self.request_ = request + + @property + def slug(self) -> str: + return self.slug_ or self.super.slug + + @property + def url_kwargs(self) -> typing.Dict[str, str]: + return self.url_kwargs_ or self.super.url_kwargs + + @property + def request(self) -> http.HttpRequest: + return self.request_ or self.super.request - # @property - # def page(self) -> Page: - # """Page from DB, that should be selected""" - # raise NotImplemented() + @property + @lru_cache(maxsize=1) + def page(self): + return ModelPage.objects.get(slug=self.slug) - def get_context_data(self, **kwargs) -> dict: - raise NotImplemented() + def get_context_data(self) -> typing.Dict[str, typing.Any]: + raise NotImplementedError class ProductsListContext(AbstractContext): @property def products(self) -> QuerySet: - raise NotImplemented() + raise NotImplementedError # TODO - fork PageContext class CategoryContext(ProductsListContext): - - # TODO - annotate it - def __init__(self, slug, request): - self.slug = slug - self.request = request - - @property - @lru_cache(maxsize=1) - def page(self): - return ModelPage.objects.get(slug=self.slug) - @property @lru_cache(maxsize=1) def products(self) -> QuerySet: @@ -98,7 +123,7 @@ def products(self) -> QuerySet: self.page.model ) - def get_context_data(self, **kwargs): + def get_context_data(self): """Add sorting options and view_types in context.""" # TODO take from dataclass or smth view_type = self.request.session.get('view_type', 'tile') @@ -117,17 +142,52 @@ def get_context_data(self, **kwargs): } -# class TaggedCategoryContext: -# def products(tags): -# return self.super.products().and_aother_fetch(catalog) -# -# def get_context_data(): -# return { -# **self.super.get_context_data(), -# ... # and something simple only about tags -# } -# -# +class TaggedCategoryContext(ProductsListContext): + + def get_sorting_index(self): + return int(self.url_kwargs.get('sorting', 0)) + + # TODO - test if it's cached + def get_tags(self) -> typing.Optional[models.TagQuerySet]: + + @lru_cache(maxsize=64) + def get_tags(request_tags_: str): + slugs = models.Tag.parse_url_tags(request_tags_) + return models.Tag.objects.filter(slug__in=slugs) + + request_tags = self.url_kwargs.get('tags') + if not request_tags: + return None + return get_tags(request_tags) + + @property + @lru_cache(maxsize=1) + def products(self): + products = self.super.products + sorting_option = SortingOption(index=self.get_sorting_index()) + tags = self.get_tags() + if tags: + products = ( + products + .filter(tags__in=tags) + # Use distinct because filtering by QuerySet tags, + # that related with products by many-to-many relation. + # TODO - try to rm this sorting staff + .distinct(sorting_option.field) + ) + return products + + def get_context_data(self): + context = self.super.get_context_data() + tags = self.get_tags() + return { + **context, + 'tags': tags, + # TODO write comment about skip_canonical + 'skip_canonical': bool(tags), + } + + # class PaginatedCatalogContext: # ... # diff --git a/shopelectro/views/catalog.py b/shopelectro/views/catalog.py index a73be597..7a102dbf 100644 --- a/shopelectro/views/catalog.py +++ b/shopelectro/views/catalog.py @@ -189,19 +189,18 @@ def get_products(self) -> QuerySet: def get_context_data(self, **kwargs): """Add sorting options and view_types in context.""" - context_ = context.CategoryContext(self.object.slug, self.request) + context_ = context.TaggedCategoryContext() | context.CategoryContext( + self.object.slug, kwargs, self.request + ) return { **super().get_context_data(**kwargs), **context_.get_context_data(), } -class TaggedCategoryPage(CategoryPage): - - def get_sorting_index(self): - return int(self.kwargs.get('sorting', 0)) +class DBContextCategoryPage(CategoryPage): + """Process db page data as db context.""" - # TODO - test if it's cached def get_tags(self) -> typing.Optional[models.TagQuerySet]: @lru_cache(maxsize=64) @@ -214,34 +213,6 @@ def get_tags(request_tags_: str): return None return get_tags(request_tags) - def get_products(self): - products = super().get_products() - sorting_option = SortingOption(index=self.get_sorting_index()) - tags = self.get_tags() - if tags: - products = ( - products - .filter(tags__in=tags) - # Use distinct because filtering by QuerySet tags, - # that related with products by many-to-many relation. - .distinct(sorting_option.field) - ) - return products - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - tags = self.get_tags() - return { - **context, - 'tags': tags, - # TODO write comment about skip_canonical - 'skip_canonical': bool(tags), - } - - -class DBContextCategoryPage(TaggedCategoryPage): - """Process db page data as db context.""" - def get_object(self, queryset=None): page = super().get_object(queryset) @@ -252,7 +223,7 @@ def template_context(page, tag_titles, tags): 'tags': tags, } - tags = super().get_tags() + tags = self.get_tags() if tags: # TODO - move to QuerySet tag_titles = models.serialize_tags_to_title(tags)