Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

views.py 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import warnings
  2. from django.conf import settings
  3. from django.http import HttpResponsePermanentRedirect
  4. from django.shortcuts import get_object_or_404
  5. from django.views.generic import ListView, DetailView
  6. from django.db.models import get_model
  7. from django.utils.translation import ugettext_lazy as _
  8. from oscar.core.loading import get_class
  9. from oscar.apps.catalogue.signals import product_viewed, product_search
  10. Product = get_model('catalogue', 'product')
  11. ProductReview = get_model('reviews', 'ProductReview')
  12. Category = get_model('catalogue', 'category')
  13. ProductAlert = get_model('customer', 'ProductAlert')
  14. ProductAlertForm = get_class('customer.forms', 'ProductAlertForm')
  15. class ProductDetailView(DetailView):
  16. context_object_name = 'product'
  17. model = Product
  18. view_signal = product_viewed
  19. template_folder = "catalogue"
  20. def get(self, request, **kwargs):
  21. """
  22. Ensures that the correct URL is used before rendering a response
  23. """
  24. self.object = product = self.get_object()
  25. if product.is_variant:
  26. return HttpResponsePermanentRedirect(
  27. product.parent.get_absolute_url())
  28. correct_path = product.get_absolute_url()
  29. if correct_path != request.path:
  30. return HttpResponsePermanentRedirect(correct_path)
  31. response = super(ProductDetailView, self).get(request, **kwargs)
  32. self.send_signal(request, response, product)
  33. return response
  34. def get_object(self, queryset=None):
  35. # Check if self.object is already set to prevent unnecessary DB calls
  36. if hasattr(self, 'object'):
  37. return self.object
  38. else:
  39. return super(ProductDetailView, self).get_object(queryset)
  40. def get_context_data(self, **kwargs):
  41. ctx = super(ProductDetailView, self).get_context_data(**kwargs)
  42. ctx['reviews'] = self.get_reviews()
  43. ctx['alert_form'] = self.get_alert_form()
  44. ctx['has_active_alert'] = self.get_alert_status()
  45. return ctx
  46. def get_alert_status(self):
  47. # Check if this user already have an alert for this product
  48. has_alert = False
  49. if self.request.user.is_authenticated():
  50. alerts = ProductAlert.objects.filter(
  51. product=self.object, user=self.request.user,
  52. status=ProductAlert.ACTIVE)
  53. has_alert = alerts.count() > 0
  54. return has_alert
  55. def get_alert_form(self):
  56. return ProductAlertForm(
  57. user=self.request.user, product=self.object)
  58. def get_reviews(self):
  59. return self.object.reviews.filter(status=ProductReview.APPROVED)
  60. def send_signal(self, request, response, product):
  61. self.view_signal.send(
  62. sender=self, product=product, user=request.user, request=request,
  63. response=response)
  64. def get_template_names(self):
  65. """
  66. Return a list of possible templates.
  67. We try 2 options before defaulting to catalogue/detail.html:
  68. 1). detail-for-upc-<upc>.html
  69. 2). detail-for-class-<classname>.html
  70. This allows alternative templates to be provided for a per-product
  71. and a per-item-class basis.
  72. """
  73. return [
  74. '%s/detail-for-upc-%s.html' % (
  75. self.template_folder, self.object.upc),
  76. '%s/detail-for-class-%s.html' % (
  77. self.template_folder, self.object.get_product_class().slug),
  78. '%s/detail.html' % (self.template_folder)]
  79. def get_product_base_queryset():
  80. """
  81. Deprecated. Kept only for backwards compatibility.
  82. Product.browsable.base_queryset() should be used instead.
  83. """
  84. warnings.warn(("`get_product_base_queryset` is deprecated in favour of"
  85. "`base_queryset` on Product's managers. It will be removed"
  86. "in Oscar 0.7."), DeprecationWarning)
  87. return Product.browsable.base_queryset()
  88. class ProductCategoryView(ListView):
  89. """
  90. Browse products in a given category
  91. Category URLs used to be based on solely the slug. Renaming the category
  92. or any of the parent categories would break the URL. Hence, the new URLs
  93. consist of both the slug and category PK (compare product URLs).
  94. The legacy way still works to not break existing systems.
  95. """
  96. context_object_name = "products"
  97. template_name = 'catalogue/browse.html'
  98. paginate_by = settings.OSCAR_PRODUCTS_PER_PAGE
  99. def get_object(self):
  100. if 'pk' in self.kwargs:
  101. self.category = get_object_or_404(Category, pk=self.kwargs['pk'])
  102. else:
  103. self.category = get_object_or_404(Category,
  104. slug=self.kwargs['category_slug'])
  105. def get(self, request, *args, **kwargs):
  106. self.get_object()
  107. correct_path = self.category.get_absolute_url()
  108. if correct_path != request.path:
  109. return HttpResponsePermanentRedirect(correct_path)
  110. self.categories = self.get_categories()
  111. return super(ProductCategoryView, self).get(request, *args, **kwargs)
  112. def get_categories(self):
  113. """
  114. Return a list of the current category and it's ancestors
  115. """
  116. categories = list(self.category.get_descendants())
  117. categories.append(self.category)
  118. return categories
  119. def get_context_data(self, **kwargs):
  120. context = super(ProductCategoryView, self).get_context_data(**kwargs)
  121. context['categories'] = self.categories
  122. context['category'] = self.category
  123. context['summary'] = self.category.name
  124. return context
  125. def get_queryset(self):
  126. return Product.browsable.base_queryset().filter(
  127. categories__in=self.categories
  128. ).distinct()
  129. class ProductListView(ListView):
  130. """
  131. A list of products
  132. """
  133. context_object_name = "products"
  134. template_name = 'catalogue/browse.html'
  135. paginate_by = settings.OSCAR_PRODUCTS_PER_PAGE
  136. search_signal = product_search
  137. model = Product
  138. def get_search_query(self):
  139. q = self.request.GET.get('q', None)
  140. return q.strip() if q else q
  141. def get_queryset(self):
  142. q = self.get_search_query()
  143. qs = Product.browsable.base_queryset()
  144. if q:
  145. # Send signal to record the view of this product
  146. self.search_signal.send(sender=self, query=q, user=self.request.user)
  147. return qs.filter(title__icontains=q)
  148. else:
  149. return qs
  150. def get_context_data(self, **kwargs):
  151. context = super(ProductListView, self).get_context_data(**kwargs)
  152. q = self.get_search_query()
  153. if not q:
  154. context['summary'] = _('All products')
  155. else:
  156. context['summary'] = _("Products matching '%(query)s'") % {'query': q}
  157. context['search_term'] = q
  158. return context