-
Notifications
You must be signed in to change notification settings - Fork 5
/
catalog.py
216 lines (175 loc) · 7.07 KB
/
catalog.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
import typing
from django import http
from django.conf import settings
from django.shortcuts import render
from django.urls import reverse
from django.views.decorators.http import require_POST
from django_user_agents.utils import get_user_agent
from catalog import context
from catalog.views import catalog
from images.models import Image
# can't do `import pages` because of django error.
# Traceback: https://gist.github.com/duker33/685e8a9f59fc5dbd243e297e77aaca42
from pages import models as pages_models, views as pages_views
from shopelectro import context as se_context, models, request_data
from shopelectro.exception import Http400
from shopelectro.views.helpers import set_csrf_cookie
def category_matrix(request, page: str):
context_ = {
'matrix_blocks': models.MatrixBlock.objects.blocks(),
'page': pages_models.CustomPage.objects.get(slug=page),
}
return render(request, 'catalog/catalog.html', context_)
@set_csrf_cookie
class ProductPage(catalog.ProductPage):
pk_url_kwarg = None
slug_url_kwarg = 'product_vendor_code'
slug_field = 'vendor_code'
queryset = (
models.Product.objects.active()
.filter(category__isnull=False)
.prefetch_related('product_feedbacks', 'page__images')
.select_related('page')
)
@property
def product(self):
return self.object
def get(self, request, *args, **kwargs):
try:
self.object = self.get_object()
except http.Http404 as error404:
response_404 = self.render_siblings_on_404(request, **kwargs)
if response_404:
return response_404
else:
raise error404
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
def get_context_data(self, **kwargs):
context_ = super(ProductPage, self).get_context_data(**kwargs)
if not self.product.page.is_active:
# this context required to render 404 page
# with it's own logic
return context_
tile_products = self.product.get_siblings(
offset=settings.PRODUCT_SIBLINGS_COUNT
)
product_images = self.get_images_context_data(tile_products)
return {
**context_,
**product_images,
'group_tags_pairs': self.product.get_params().items(),
'tile_products': tile_products,
'tile_title': 'Вас может заинтересовать',
}
def get_images_context_data(self, products) -> dict:
"""Return images for given products."""
products_to_filter = [self.product, *products]
return context.products.ProductImages(
products_to_filter, Image.objects.all(),
).context()
def render_siblings_on_404(
self, request, **url_kwargs
) -> typing.Union[http.Http404, None]:
"""Try to render removed product's siblings on it's 404 page."""
inactive_product = models.Product.objects.filter(
**{self.slug_field: url_kwargs['product_vendor_code']},
category__isnull=False,
page__is_active=False
).first()
if inactive_product:
siblings = inactive_product.get_siblings(
offset=settings.PRODUCT_SIBLINGS_COUNT
)
self.object = inactive_product
context_ = self.get_context_data(
object=inactive_product,
tile_products=siblings,
tile_title='Возможно вас заинтересуют похожие товары:',
**url_kwargs,
)
context_.update(self.get_images_context_data(siblings))
return render(request, 'catalog/product_404.html', context_, status=404)
# SHOPELECTRO-SPECIFIC VIEWS
@set_csrf_cookie
class IndexPage(pages_views.CustomPageView):
@staticmethod
def get_categories_tile():
"""Patch every link with url, generated from slug."""
return {section: [
{**link, 'url': (
reverse('category', kwargs={'slug': link['slug']})
if link.get('slug') and not link.get('url')
else link['url']
)} for link in links
] for section, links in settings.MAIN_PAGE_TILE.items()}
def get_context_data(self, **kwargs):
"""Extended method. Add product's images to context."""
context_ = super(IndexPage, self).get_context_data(**kwargs)
mobile_view = get_user_agent(self.request).is_mobile
tile_products = []
top_products = (
models.Product.objects.active()
.bind_fields()
.filter(id__in=settings.TOP_PRODUCTS)
)
if not mobile_view:
tile_products = top_products
images_ctx = context.products.ProductImages(
tile_products,
Image.objects.all(),
).context()
return {
**context_,
**images_ctx,
'tile_title': 'ТОП 10 ТОВАРОВ',
'category_tile': self.get_categories_tile(),
'tile_products': tile_products,
}
@set_csrf_cookie
class CategoryPage(catalog.CategoryPageTemplate):
def get_context_data(self, **kwargs):
"""Add sorting options and view_types in context."""
request_data_ = request_data.Catalog(self.request, self.kwargs)
return {
**super().get_context_data(**kwargs),
**se_context.Catalog(request_data_).context(),
}
def load_more(request, **url_kwargs):
try:
request_data_ = request_data.LoadMore(request, url_kwargs)
except Http400:
return http.HttpResponseBadRequest(
'The offset is wrong. An offset should be greater than or equal to 0.'
)
return render(
request,
'catalog/category_products.html',
se_context.Catalog(request_data_).context()
)
@require_POST
def save_feedback(request):
def get_keys_from_post(*args):
return {arg: request.POST.get(arg, '') for arg in args}
product_id = request.POST.get('id')
product = models.Product.objects.filter(id=product_id, page__is_active=True).first()
if not (product_id and product):
return http.HttpResponse(status=422)
fields = ['rating', 'name', 'dignities', 'limitations', 'general']
feedback_data = get_keys_from_post(*fields)
models.ProductFeedback.objects.create(product=product, **feedback_data)
return http.HttpResponse('ok')
@require_POST
def delete_feedback(request):
if not request.user.is_authenticated:
return http.HttpResponseForbidden('Not today, sly guy...')
feedback_id = request.POST.get('id')
feedback = models.ProductFeedback.objects.filter(id=feedback_id).first()
if not (feedback_id and feedback):
return http.HttpResponse(status=422)
feedback.delete()
return http.HttpResponse('Feedback with id={} was deleted.'.format(feedback_id))
class ProductsWithoutImages(catalog.ProductsWithoutImages):
model = models.Product
class ProductsWithoutText(catalog.ProductsWithoutText):
model = models.Product