diff --git a/.gitignore b/.gitignore
index a91c0c66..1b3e2edb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,5 @@ package-lock.json
report.xml
database
*.orig
+*.sublime-project
+*.sublime-workspace
diff --git a/stroyprombeton/context/__init__.py b/stroyprombeton/context/__init__.py
index fc4df825..a063d1ec 100644
--- a/stroyprombeton/context/__init__.py
+++ b/stroyprombeton/context/__init__.py
@@ -1 +1,2 @@
from .catalog import *
+from . import options, tags
diff --git a/stroyprombeton/context/catalog.py b/stroyprombeton/context/catalog.py
index ec5fa92e..40eaa9dd 100644
--- a/stroyprombeton/context/catalog.py
+++ b/stroyprombeton/context/catalog.py
@@ -15,8 +15,7 @@
from catalog import context, typing
from images.models import Image
from pages import context as pages_context
-from stroyprombeton import models as stb_models, request_data
-from stroyprombeton.context import options
+from stroyprombeton import models as stb_models, context as stb_context, request_data
class TagsByOptions(context.Tags):
@@ -75,13 +74,9 @@ def category(self):
id=self.request_data.id
)
- @property
- def tags(self) -> context.Tags:
- return context.Tags(stb_models.Tag.objects.all())
-
def context(self) -> typing.ContextDict:
tags = FilteredTags(stb_models.Tag.objects.all(), self.request_data)
- options_ = options.Filtered(self.category, tags.qs(), self.request_data)
+ options_ = stb_context.options.Filtered(self.category, tags.qs())
if not options_.qs():
raise http.Http404('
В категории нет изделий
typing.ContextDict:
sliced_options.products, Image.objects.all()
)
grouped_tags = context.tags.GroupedTags(
- tags=TagsByOptions(self.tags, options_.qs())
+ tags=TagsByOptions(stb_context.tags.All(), options_.qs())
)
page = Page(self.page, tags)
category = CategoryContext(self.request_data)
@@ -162,12 +157,12 @@ def __init__(self, request_data_: request_data.FetchProducts):
def context(self) -> typing.ContextDict:
category = CategoryContext(self.request_data)
tags = FilteredTags(stb_models.Tag.objects.all(), self.request_data)
- options_ = options.Sliced(
+ options_ = stb_context.options.Sliced(
request_data_=self.request_data,
- options=options.Searched(
+ options=stb_context.options.Searched(
request_data_=self.request_data,
- options=options.Filtered(
- category.object(), tags.qs(), self.request_data
+ options=stb_context.options.Filtered(
+ category.object(), tags.qs(),
)
)
)
diff --git a/stroyprombeton/context/options.py b/stroyprombeton/context/options.py
index ca7ffb2c..c0105646 100644
--- a/stroyprombeton/context/options.py
+++ b/stroyprombeton/context/options.py
@@ -49,28 +49,74 @@ def context(self) -> typing.ContextDict:
}
-class Filtered(Options):
+class All(Options):
+
+ def __init__(self, qs: stb_models.OptionQuerySet = None):
+ self._qs = qs or stb_models.Option.objects.all()
+
+ def qs(self) -> stb_models.OptionQuerySet:
+ return (
+ self._qs
+ .bind_fields()
+ .active()
+ .order_by(*settings.OPTIONS_ORDERING)
+ )
+
+
+class CategoryFiltered(Options):
+
def __init__(
self,
- category: stb_models.Category,
- tags: stb_models.TagQuerySet,
- request_data_: request_data.Category
+ options: Options,
+ category: stb_models.Category
):
+ self.options = options
self.category = category
- self.tags = tags
- self.request_data = request_data_
def qs(self) -> stb_models.OptionQuerySet:
return (
- stb_models.Option.objects
- .bind_fields()
- .active()
+ self.options
+ .qs()
.filter_descendants(self.category)
+ )
+
+
+class TagsFiltered(Options):
+ def __init__(
+ self,
+ options: Options,
+ tags: stb_models.TagQuerySet,
+ ):
+ self.options = options
+ self.tags = tags
+
+ def qs(self) -> stb_models.OptionQuerySet:
+ return (
+ self.options
+ .qs()
.tagged_or_all(self.tags)
- .order_by(*settings.OPTIONS_ORDERING)
)
+class Filtered(Options):
+ def __init__(
+ self,
+ category: stb_models.Category,
+ tags: stb_models.TagQuerySet,
+ ):
+ """Filtered options by a category and tags."""
+ self.filtered = TagsFiltered(
+ CategoryFiltered(
+ All(),
+ category,
+ ),
+ tags,
+ )
+
+ def qs(self) -> stb_models.OptionQuerySet:
+ return self.filtered.qs()
+
+
class Searched(Options):
LOOKUPS = [
diff --git a/stroyprombeton/context/tags.py b/stroyprombeton/context/tags.py
new file mode 100644
index 00000000..af68418a
--- /dev/null
+++ b/stroyprombeton/context/tags.py
@@ -0,0 +1,13 @@
+from catalog import context
+from stroyprombeton import models as stb_models
+
+# @todo #744:30m Move all tags related context classes in this file.
+
+
+class All(context.Tags):
+
+ def __init__(self, qs: stb_models.TagQuerySet = None):
+ self._qs = qs or stb_models.Tag.objects.all()
+
+ def qs(self) -> stb_models.OptionQuerySet:
+ return self._qs
diff --git a/stroyprombeton/tests/tests_views.py b/stroyprombeton/tests/tests_views.py
index 64338741..06b839a7 100644
--- a/stroyprombeton/tests/tests_views.py
+++ b/stroyprombeton/tests/tests_views.py
@@ -741,13 +741,36 @@ class ProductPrice(TestCase):
fixtures = ['dump.json']
- def test_price_list(self):
- """Context for pdf generation should include Category and Products."""
- self.response = self.client.get('/gbi/categories/1/pdf/')
+ def setUp(self):
+ self.category = models.CategoryPage.objects.filter(level=0).first()
+ self.response = self.client.get(
+ reverse('product_pdf', args=(self.category.id,))
+ )
+ self.context = self.response.context
+
+ def test_content_type(self):
+ self.assertEqual(self.response['Content-Type'], 'application/pdf')
+
+ def test_category_name(self):
+ self.assertEqual(self.context['category'].name, self.category.name)
+
+ def test_products(self):
+ self.assertIsInstance(self.context['products'], models.OptionQuerySet)
+ self.assertGreater(self.context['products'].count(), 100)
+
+ def test_tags_are_grouped(self):
+ for group, tags in self.context['group_tags_pairs']:
+ for tag_ in tags:
+ self.assertEqual(group, tag_.group)
+
+ def test_product_tags(self):
+ tags = set(chain.from_iterable(
+ grouped_tags
+ for _, grouped_tags in self.context['group_tags_pairs']
+ ))
- self.assertTrue(self.response['Content-Type'] == 'application/pdf')
- self.assertTrue(self.response.context['category'].name == CATEGORY_ROOT_NAME)
- self.assertTrue(len(self.response.context['products']) > 100)
+ for product in self.context['products'].filter(tags__isnull=False):
+ self.assertTrue(tags & set(product.tags.all()))
@tag('fast', 'catalog')
diff --git a/stroyprombeton/views/catalog.py b/stroyprombeton/views/catalog.py
index ccd77bb2..36e05cfb 100644
--- a/stroyprombeton/views/catalog.py
+++ b/stroyprombeton/views/catalog.py
@@ -13,6 +13,7 @@
from catalog import context
from catalog.views import catalog
from images.models import Image
+from pages import context as pages_context
from pages.models import CustomPage, ModelPage
from pages.templatetags.pages_extras import breadcrumbs as get_page_breadcrumbs
from stroyprombeton import context as stb_context, models, exception, request_data
@@ -192,24 +193,29 @@ class ProductPDF(PDFTemplateView, DetailView):
def get(self, *args, **kwargs):
self.object = self.get_object()
- return super(ProductPDF, self).get(*args, **kwargs)
+ return super().get(*args, **kwargs)
def get_context_data(self, **kwargs):
- context = super(ProductPDF, self).get_context_data(**kwargs)
- category = context[self.context_object_name]
+ context_ = super().get_context_data(**kwargs)
+ category = context_[self.context_object_name]
- products = (
- models.Product.objects
- .active()
- .filter_descendants(category)
- # use `OPTIONS_ORDERING` instead
- # .order_by(*settings.PRODUCTS_ORDERING)
+ options_ = stb_context.options.CategoryFiltered(
+ stb_context.options.All(),
+ category
+ )
+ grouped_tags = context.tags.GroupedTags(
+ tags=stb_context.TagsByOptions(
+ stb_context.tags.All(),
+ options_.qs(),
+ )
)
return {
- **context,
+ **context_,
+ **pages_context.Contexts([
+ options_, grouped_tags,
+ ]).context(),
'category': category,
- 'products': products,
}
diff --git a/templates/catalog/product_pdf_price.html b/templates/catalog/product_pdf_price.html
index 32b878b7..f2cd847f 100644
--- a/templates/catalog/product_pdf_price.html
+++ b/templates/catalog/product_pdf_price.html
@@ -4,7 +4,6 @@
-