forked from awesto/django-shop
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathviews.py
135 lines (105 loc) · 5.5 KB
/
views.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
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
from rest_framework.mixins import ListModelMixin
from rest_framework.renderers import BrowsableAPIRenderer
from rest_framework.settings import api_settings
from drf_haystack.generics import HaystackGenericAPIView
from shop.conf import app_settings
from shop.models.product import ProductModel
from shop.rest.filters import CMSPagesFilterBackend
from shop.rest.renderers import CMSPageRenderer
from shop.rest.money import JSONRenderer
from shop.views.catalog import ProductListView, ProductListPagination, AddFilterContextMixin
class SearchView(ListModelMixin, HaystackGenericAPIView):
"""
A generic view to be used for rendering the result list while searching.
"""
renderer_classes = [CMSPageRenderer, JSONRenderer, BrowsableAPIRenderer]
pagination_class = ProductListPagination
serializer_class = None # to be set by SearchView.as_view(serializer_class=...)
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def get_template_names(self):
return [self.request.current_page.get_template()]
class CMSPageSearchMixin(object):
"""
Mixin to restrict search results to products associated with the current CMS page only
"""
def get_queryset(self, index_models=[]):
current_page = self.request.current_page
if current_page.publisher_is_draft:
current_page = current_page.publisher_public
queryset = super(SearchView, self).get_queryset(index_models)
return queryset.filter(categories=current_page.pk)
class AddSearchContextMixin(object):
"""
A mixin that can be used to enrich the render context by ``autocomplete``, so that
templates can decide weather to add a search field or not.
"""
def get_renderer_context(self):
renderer_context = super(AddSearchContextMixin, self).get_renderer_context()
if renderer_context['request'].accepted_renderer.format == 'html':
renderer_context['search_autocomplete'] = True
return renderer_context
class CMSPageCatalogWrapper(object):
"""
Wraps the view classes :class:`shop.views.catalog.ProductListView` and
:class:`shop.search.views.SearchView` into a callable which behaves like a
Django View class, but dispatches requests between both of them depending on
the query params.
Usage: Add it to the urlpatterns responsible for rendering the catalog's list view:
```
urlpatterns = [
url(r'^$', CMSPageCatalogWrapper.as_view(
filter_class=CustomFilterSet,
)),
```
In addition to ``filter_class`` you may override other attributes:
:param renderer_classes: A list or tuple of REST renderer classes.
:param product_model: The product model onto which the filter set is applied.
:param limit_choices_to: Limit the queryset of product models to these choices.
:param filter_class: A filter set which must inherit from :class:`django_filters.FilterSet`.
:param search_serializer_class: The serializer class used to process the queryset returned
by Haystack, while performing an autocomplete lookup.
:param model_serializer_class: The serializer class used to process the queryset returned
by the catalog's product list view, while using a filter set.
:param filter_backends: The filter backends used to narrow down the catalog's product list view.
:param cms_pages_fields: Specify the fields used by the Product model to assign them to
categories.
"""
renderer_classes = (CMSPageRenderer, JSONRenderer, BrowsableAPIRenderer)
product_model = ProductModel
limit_choices_to = models.Q()
search_serializer_class = None # must be overridden by CMSPageCatalogWrapper.as_view()
model_serializer_class = app_settings.PRODUCT_SUMMARY_SERIALIZER # may be overridden by CMSPageCatalogWrapper.as_view()
filter_class = None # may be overridden by CMSPageCatalogWrapper.as_view()
filter_backends = [CMSPagesFilterBackend] + list(api_settings.DEFAULT_FILTER_BACKENDS)
cms_pages_fields = ['cms_pages']
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
@classmethod
def as_view(cls, **initkwargs):
for key in initkwargs:
if not hasattr(cls, key):
msg = "{0}() received an invalid keyword {1}. Method as_view() only " \
" accepts arguments that are already attributes of the class."
raise TypeError(msg.format(cls.__name__, key))
self = cls(**initkwargs)
bases = (AddFilterContextMixin, AddSearchContextMixin, CMSPageSearchMixin, SearchView)
attrs = dict(renderer_classes=self.renderer_classes, product_model=self.product_model,
limit_choices_to=self.limit_choices_to, filter_class=self.filter_class)
self.search_view = type(str('CatalogSearchView'), bases, attrs).as_view(
serializer_class=self.search_serializer_class,
)
bases = (AddFilterContextMixin, AddSearchContextMixin, ProductListView)
attrs.update(filter_backends=self.filter_backends, cms_pages_fields=self.cms_pages_fields)
self.list_view = type(str('CatalogListView'), bases, attrs).as_view(
serializer_class=self.model_serializer_class,
)
return self
def __call__(self, request):
if request.GET.get('q'):
return self.search_view(request)
return self.list_view(request)