From 8d4112218802d48473fc8c7a06c92271ac8772d4 Mon Sep 17 00:00:00 2001 From: duker Date: Fri, 31 Aug 2018 14:43:03 +0300 Subject: [PATCH] #550 Implement CatalogContext --- shopelectro/context.py | 155 +++++++++++++++++++++++++++++++++++ shopelectro/views/catalog.py | 21 +---- 2 files changed, 159 insertions(+), 17 deletions(-) create mode 100644 shopelectro/context.py diff --git a/shopelectro/context.py b/shopelectro/context.py new file mode 100644 index 00000000..7daf610d --- /dev/null +++ b/shopelectro/context.py @@ -0,0 +1,155 @@ +""" +Contains view context classes. +Context is part of the View abstract layer in MTV paradigm. +It stands between urls and view functions. + +Every context class is used via objects composition. +For example: +TODO - add example of objects composition +""" + +import typing +from functools import lru_cache, partial + +from django import http +from django.db.models import QuerySet +from django.conf import settings +from django.core.paginator import Paginator, InvalidPage +from django.shortcuts import render, get_object_or_404 +from django.views.decorators.http import require_POST +from django_user_agents.utils import get_user_agent + +from catalog.views import catalog +from images.models import Image +from pages import views as pages_views + +from shopelectro import models +from shopelectro.views.helpers import set_csrf_cookie + +from pages.models import ModelPage, Page + + +@lru_cache(maxsize=64) +def merge_products_context(products): + images = Image.objects.get_main_images_by_pages( + models.ProductPage.objects.filter(shopelectro_product__in=products) + ) + + # TODO - create product.get_brand instead + brands = ( + models.Tag.objects + .filter_by_products(products) + .get_brands(products) + ) + + return [ + (product, images.get(product.page), brands.get(product)) + for product in products + ] + + +class ObjectsComposition: + + super = object() + + def __or__(self, other): + self.super = other + + +class AbstractContext(ObjectsComposition): + + # TODO - raise not implemented here + # @property + # def request(self): + # raise NotImplemented() + + # @property + # def page(self) -> Page: + # """Page from DB, that should be selected""" + # raise NotImplemented() + + def get_context_data(self, **kwargs) -> dict: + raise NotImplemented() + + +class ProductsListContext(AbstractContext): + @property + def products(self) -> QuerySet: + raise NotImplemented() + + +# 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: + return models.Product.actives.get_category_descendants( + self.page.model + ) + + def get_context_data(self, **kwargs): + """Add sorting options and view_types in context.""" + # TODO take from dataclass or smth + view_type = self.request.session.get('view_type', 'tile') + + group_tags_pairs = ( + models.Tag.objects + .filter_by_products(self.products) + .get_group_tags_pairs() + ) + + return { + 'products_data': merge_products_context(self.products), + 'group_tags_pairs': group_tags_pairs, + # TODO add comment about view_type + 'view_type': view_type, + } + + +# 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 PaginatedCatalogContext: +# ... +# +# +# class DBTemplateContext: +# ... +# +# +# class CatalogView: +# def get_context_data(category_id, page_num): +# category = some_fetch(category_id) +# context = CatalogContext(category) | PaginatedCatalogContext(page_num) +# return context.get_context_data() +# +# +# class TaggedCatalogView: +# def get_context_data(category_id, page_num, tags): +# category = some_fetch(category_id) +# context = ( +# CatalogContext(category) +# | PaginatedCatalogContext(page_num) +# | TaggedCatalogContext(tags) +# | DBTemplateContext(tags) +# ) +# return context.get_context_data() diff --git a/shopelectro/views/catalog.py b/shopelectro/views/catalog.py index a32e7679..a73be597 100644 --- a/shopelectro/views/catalog.py +++ b/shopelectro/views/catalog.py @@ -13,7 +13,7 @@ from images.models import Image from pages import views as pages_views -from shopelectro import models +from shopelectro import context, models from shopelectro.views.helpers import set_csrf_cookie PRODUCTS_ON_PAGE_PC = 48 @@ -189,23 +189,10 @@ def get_products(self) -> QuerySet: def get_context_data(self, **kwargs): """Add sorting options and view_types in context.""" - # TODO take from dataclass or smth - view_type = self.request.session.get('view_type', 'tile') - context = super().get_context_data(**kwargs) - - products = self.get_products() - group_tags_pairs = ( - models.Tag.objects - .filter_by_products(products) - .get_group_tags_pairs() - ) - + context_ = context.CategoryContext(self.object.slug, self.request) return { - **context, - 'products_data': merge_products_context(products), - 'group_tags_pairs': group_tags_pairs, - # TODO add comment about view_type - 'view_type': view_type, + **super().get_context_data(**kwargs), + **context_.get_context_data(), }