Skip to content

Commit

Permalink
#550 Merge fixes after hell
Browse files Browse the repository at this point in the history
  • Loading branch information
duker33 committed Sep 6, 2018
1 parent 70bb062 commit 415a344
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 126 deletions.
49 changes: 48 additions & 1 deletion shopelectro/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,42 @@ def directed_field(self):
return self.direction + self.field


# @todo #539:60m Move PaginatorLinks to refarm-site.
class PaginatorLinks:

def __init__(self, number, path, paginated: Paginator):
self.paginated = paginated
self.number = number
self.path = path

self.index = number - 1
self.neighbor_bounds = settings.PAGINATION_NEIGHBORS // 2
self.neighbor_range = list(self.paginated.page_range)

def page(self):
try:
return self.paginated.page(self.number)
except InvalidPage:
raise http.Http404('Page does not exist')

def showed_number(self):
return self.index * self.paginated.per_page + self.page().object_list.count()

def _url(self, number):
self.paginated.validate_number(number)
return self.path if number == 1 else f'{self.path}?page={number}'

def prev_numbers(self):
return self.neighbor_range[:self.index][-self.neighbor_bounds:]

def next_numbers(self):
return self.neighbor_range[self.index + 1:][:self.neighbor_bounds]

def number_url_map(self):
numbers = self.prev_numbers() + self.next_numbers()
return {number: self._url(number) for number in numbers}


# @todo #550:30m Split to ProductImagesContext and ProductBrandContext
@lru_cache(maxsize=64)
def merge_products_context(products: QuerySet):
Expand Down Expand Up @@ -194,7 +230,10 @@ def get_tags(request_tags_: str):
request_tags = self.url_kwargs.get('tags')
if not request_tags:
return None
return get_tags(request_tags)
tags = get_tags(request_tags)
if not tags:
raise http.Http404('No such tag.')
return tags

@property
def products(self):
Expand Down Expand Up @@ -317,11 +356,19 @@ def get_context_data(self):
if not products:
raise http.Http404('Page without products does not exist.')

paginated = PaginatorLinks(
page_number,
self.request.path,
Paginator(self.products, products_on_page)
)
paginated_page = paginated.page()

return {
**context,
'products_data': merge_products_context(products),
'total_products': total_products,
'products_count': (page_number - 1) * products_on_page + products.count(),
'paginated': paginated,
'paginated_page': paginated_page,
'sorting_options': settings.CATEGORY_SORTING_OPTIONS.values(),
'limits': settings.CATEGORY_STEP_MULTIPLIERS,
Expand Down
24 changes: 18 additions & 6 deletions shopelectro/models.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
from typing import Optional
import random
import string
from itertools import chain, groupby
from operator import attrgetter
import typing
from uuid import uuid4

from django.conf import settings
from django.db import models
from django.urls import reverse
from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _
from mptt.querysets import TreeQuerySet
from unidecode import unidecode

from catalog.models import (
AbstractCategory,
AbstractProduct,
CategoryManager,
ProductActiveManager,
ProductManager,
Tag as caTag,
TagGroup as caTagGroup,
)
from ecommerce.models import Order as ecOrder
from pages.models import CustomPage, ModelPage, Page, SyncPageMixin, PageManager


def randomize_slug(slug: str) -> str:
slug_hash = ''.join(
random.choices(string.ascii_lowercase, k=settings.SLUG_HASH_SIZE)
)
return f'{slug}_{slug_hash}'


class SECategoryQuerySet(TreeQuerySet):
def get_categories_tree_with_pictures(self) -> 'SECategoryQuerySet':
categories_with_pictures = (
Expand Down Expand Up @@ -109,7 +121,7 @@ def get_params(self):
return Tag.objects.filter_by_products([self]).get_group_tags_pairs()

def get_brand_name(self) -> str:
brand: Optional['Tag'] = Tag.objects.get_brands([self]).get(self)
brand: typing.Optional['Tag'] = Tag.objects.get_brands([self]).get(self)
return brand.name if brand else ''


Expand Down Expand Up @@ -199,7 +211,7 @@ def __str__(self):

class TagQuerySet(models.QuerySet):

def filter_by_products(self, products: List[Product]):
def filter_by_products(self, products: typing.List[Product]):
ordering = settings.TAGS_ORDER
distinct = [order.lstrip('-') for order in ordering]

Expand All @@ -210,14 +222,14 @@ def filter_by_products(self, products: List[Product]):
.distinct(*distinct, 'id')
)

def get_group_tags_pairs(self) -> List[Tuple[TagGroup, List['Tag']]]:
def get_group_tags_pairs(self) -> typing.List[typing.Tuple[TagGroup, typing.List['Tag']]]:
grouped_tags = groupby(self.prefetch_related('group'), key=attrgetter('group'))
return [
(group, list(tags_))
for group, tags_ in grouped_tags
]

def get_brands(self, products: List[Product]) -> Dict[Product, 'Tag']:
def get_brands(self, products: typing.List[Product]) -> typing.Dict[Product, 'Tag']:
brand_tags = (
self.filter(group__name=settings.BRAND_TAG_GROUP_NAME)
.prefetch_related('products')
Expand Down
131 changes: 12 additions & 119 deletions shopelectro/views/catalog.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import typing
from functools import partial
from functools import lru_cache

from django import http
from django.conf import settings
Expand All @@ -8,12 +8,11 @@
from django.views.decorators.http import require_POST
from django_user_agents.utils import get_user_agent

from catalog import models as ca_models
from catalog.views import catalog
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
Expand All @@ -26,42 +25,6 @@ def get_products_count(request):
return PRODUCTS_ON_PAGE_MOB if mobile_view else PRODUCTS_ON_PAGE_PC


# @todo #539:60m Move PaginatorLinks to refarm-site.
class PaginatorLinks:

def __init__(self, number, path, paginated: Paginator):
self.paginated = paginated
self.number = number
self.path = path

self.index = number - 1
self.neighbor_bounds = settings.PAGINATION_NEIGHBORS // 2
self.neighbor_range = list(self.paginated.page_range)

def page(self):
try:
return self.paginated.page(self.number)
except InvalidPage:
raise http.Http404('Page does not exist')

def showed_number(self):
return self.index * self.paginated.per_page + self.page().object_list.count()

def _url(self, number):
self.paginated.validate_number(number)
return self.path if number == 1 else f'{self.path}?page={number}'

def prev_numbers(self):
return self.neighbor_range[:self.index][-self.neighbor_bounds:]

def next_numbers(self):
return self.neighbor_range[self.index + 1:][:self.neighbor_bounds]

def number_url_map(self):
numbers = self.prev_numbers() + self.next_numbers()
return {number: self._url(number) for number in numbers}


class SortingOption:
def __init__(self, index=0):
options = settings.CATEGORY_SORTING_OPTIONS[index]
Expand Down Expand Up @@ -188,6 +151,7 @@ def get_context_data(self, **kwargs):
}


@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)
Expand All @@ -210,87 +174,16 @@ class CategoryPage(catalog.CategoryPage):

def get_context_data(self, **kwargs):
"""Add sorting options and view_types in context."""
context = super().get_context_data(**kwargs)
products_on_page = int(self.request.GET.get(
'step', get_products_count(self.request),
))
page_number = int(self.request.GET.get('page', 1))
view_type = self.request.session.get('view_type', 'tile')
sorting_index = int(self.kwargs.get('sorting', 0))
sorting_option = SortingOption(index=sorting_index)
category = context['category']
if (
page_number < 1 or
products_on_page not in settings.CATEGORY_STEP_MULTIPLIERS
):
raise http.Http404('Page does not exist.') # Ignore CPDBear

all_products = models.Product.actives.get_category_descendants(
category, ordering=(sorting_option.directed_field, )
)

group_tags_pairs = (
models.Tag.objects
.filter_by_products(all_products)
.get_group_tags_pairs()
context_ = (
context.Category(self.kwargs, self.request)
| context.TaggedCategory()
| context.SortingCategory()
| context.PaginationCategory() # requires SortingCategory
| context.DBTemplate() # requires TaggedCategory
)

tags = self.kwargs.get('tags')

tag_titles = ''
if tags:
slugs = models.Tag.parse_url_tags(tags)
tags = models.Tag.objects.filter(slug__in=slugs)

if not tags:
raise http.Http404('No such tag.')

all_products = (
all_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)
)

tag_titles = ca_models.serialize_tags_to_title(tags)

def template_context(page, tag_titles, tags):
return {
'page': page,
'tag_titles': tag_titles,
'tags': tags,
}

page = context['page']
page.get_template_render_context = partial(
template_context, page, tag_titles, tags)

paginated = PaginatorLinks(
page_number,
self.request.path,
Paginator(all_products, products_on_page)
)
paginated_page = paginated.page()

total_products = all_products.count()
products_on_page = paginated_page.object_list
if not products_on_page:
raise http.Http404('Page without products does not exist.')

return {
**context,
'products_data': merge_products_context(products_on_page),
'group_tags_pairs': group_tags_pairs,
'total_products': total_products,
'paginated': paginated,
'paginated_page': paginated_page,
'sorting_options': settings.CATEGORY_SORTING_OPTIONS.values(),
'limits': settings.CATEGORY_STEP_MULTIPLIERS,
'sort': sorting_index,
'tags': tags,
'view_type': view_type,
'skip_canonical': bool(tags),
**super().get_context_data(**kwargs),
**context_.get_context_data(),
}


Expand Down Expand Up @@ -339,7 +232,7 @@ def load_more(request, category_slug, offset=0, limit=0, sorting=0, tags=None):
.distinct(sorting_option.field)
)

paginated = PaginatorLinks(
paginated = context.PaginatorLinks(
page_number,
request.path,
Paginator(all_products, products_on_page)
Expand Down

0 comments on commit 415a344

Please sign in to comment.