Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

abstract_models.py 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. from django.db import models
  2. from django.conf import settings
  3. from django.utils.translation import ugettext as _
  4. from django.core.urlresolvers import reverse
  5. from django.core.exceptions import ValidationError
  6. from oscar.forms.fields import ExtendedURLField
  7. # Settings-controlled stuff
  8. BANNER_FOLDER = settings.OSCAR_BANNER_FOLDER
  9. POD_FOLDER = settings.OSCAR_POD_FOLDER
  10. BLOCK_TYPES = settings.OSCAR_PROMOTION_MERCHANDISING_BLOCK_TYPES
  11. BANNER, LEFT_POD, RIGHT_POD, RAW_HTML = ('Banner', 'Left pod', 'Right pod', 'Raw HTML')
  12. POSITION_CHOICES = (
  13. (BANNER, _("Banner")),
  14. (LEFT_POD, _("Pod on left-hand side of page")),
  15. (RIGHT_POD, _("Pod on right-hand side of page")),
  16. )
  17. class AbstractPromotion(models.Model):
  18. """
  19. A promotion model.
  20. This is effectively a link for directing users to different parts of the site.
  21. It can have two images associated with it.
  22. """
  23. name = models.CharField(_("Name"), max_length=128)
  24. link_url = ExtendedURLField(blank=True, null=True, help_text="""This is
  25. where this promotion links to""")
  26. banner_image = models.ImageField(upload_to=BANNER_FOLDER, blank=True, null=True)
  27. pod_image = models.ImageField(upload_to=POD_FOLDER, blank=True, null=True)
  28. date_created = models.DateTimeField(auto_now_add=True)
  29. _proxy_link_url = None
  30. image_html_template = '<img src="%s" alt="%s" />'
  31. link_html = '<a href="%s">%s</a>'
  32. class Meta:
  33. abstract = True
  34. ordering = ['date_created']
  35. get_latest_by = "date_created"
  36. def __unicode__(self):
  37. if not self.link_url:
  38. return self.name
  39. return "%s (%s)" % (self.name, self.link_url)
  40. def clean(self):
  41. if not self.banner_image and not self.pod_image:
  42. raise ValidationError("A promotion must have one of a banner image, pod image or raw HTML")
  43. def set_proxy_link(self, url):
  44. self._proxy_link_url = url
  45. @property
  46. def has_link(self):
  47. return self.link_url != None
  48. def get_banner_html(self):
  49. return self._get_html('banner_image')
  50. def get_pod_html(self):
  51. return self._get_html('pod_image')
  52. def _get_html(self, image_field):
  53. u"""
  54. Returns the appropriate HTML for an image field
  55. """
  56. try:
  57. image = getattr(self, image_field)
  58. image_html = self.image_html_template % (image.url, self.name)
  59. if self.link_url and self._proxy_link_url:
  60. return self.link_html % (self._proxy_link_url, image_html)
  61. return image_html
  62. except AttributeError:
  63. return ''
  64. class LinkedPromotion(models.Model):
  65. promotion = models.ForeignKey('promotions.Promotion')
  66. position = models.CharField(_("Position"), max_length=100, help_text="Position on page", choices=POSITION_CHOICES)
  67. display_order = models.PositiveIntegerField(default=0)
  68. clicks = models.PositiveIntegerField(default=0)
  69. date_created = models.DateTimeField(auto_now_add=True)
  70. class Meta:
  71. abstract = True
  72. ordering = ['-clicks']
  73. def record_click(self):
  74. self.clicks += 1
  75. self.save()
  76. class AbstractPagePromotion(LinkedPromotion):
  77. u"""
  78. A promotion embedded on a particular page.
  79. """
  80. page_url = ExtendedURLField(max_length=128, db_index=True)
  81. class Meta:
  82. abstract = True
  83. def __unicode__(self):
  84. return u"%s on %s" % (self.promotion, self.page_url)
  85. def get_link(self):
  86. return reverse('oscar-page-promotion-click', kwargs={'page_promotion_id': self.id})
  87. class AbstractKeywordPromotion(LinkedPromotion):
  88. u"""
  89. A promotion linked to a specific keyword.
  90. This can be used on a search results page to show promotions
  91. linked to a particular keyword.
  92. """
  93. keyword = models.CharField(_("Keyword"), max_length=200)
  94. class Meta:
  95. abstract = True
  96. def get_link(self):
  97. return reverse('oscar-keyword-promotion-click', kwargs={'keyword_promotion_id': self.id})
  98. class AbstractMerchandisingBlock(models.Model):
  99. title = models.CharField(_("Title"), max_length=255)
  100. description = models.TextField(null=True, blank=True)
  101. type = models.CharField(_("Type"), choices=BLOCK_TYPES, max_length=100)
  102. products = models.ManyToManyField('product.Item', through='MerchandisingBlockProduct', blank=True, null=True)
  103. link_url = ExtendedURLField(max_length=128, blank=True, null=True)
  104. date_created = models.DateTimeField(auto_now_add=True)
  105. class Meta:
  106. abstract = True
  107. def __unicode__(self):
  108. return self.title
  109. def template_context(self, *args, **kwargs):
  110. """
  111. Returns dynamically generated HTML that isn't product related.
  112. This can be used for novel forms of block.
  113. """
  114. method = 'template_context_%s' % self.type.lower()
  115. if hasattr(self, method):
  116. return getattr(self, method)(*args, **kwargs)
  117. return {}
  118. def template_context_tabbedblock(self, *args, **kwargs):
  119. # Split into groups
  120. groups = {}
  121. match = 0
  122. counter = 0
  123. for blockproduct in MerchandisingBlockProduct.objects.filter(block=self):
  124. if blockproduct.group not in groups:
  125. groups[blockproduct.group] = {'name': blockproduct.group,
  126. 'products': []}
  127. if match and blockproduct.group == match:
  128. groups[blockproduct.group]['is_visible'] = True
  129. elif not match and counter == 0:
  130. groups[blockproduct.group]['is_visible'] = True
  131. else:
  132. groups[blockproduct.group]['is_visible'] = False
  133. groups[blockproduct.group]['products'].append(blockproduct.product)
  134. counter += 1
  135. return {'groups': groups.values()}
  136. @property
  137. def num_products(self):
  138. return self.products.all().count()
  139. @property
  140. def template_file(self):
  141. return 'oscar/promotions/block_%s.html' % self.type.lower()
  142. class MerchandisingBlockProduct(models.Model):
  143. block = models.ForeignKey('promotions.MerchandisingBlock')
  144. product = models.ForeignKey('product.Item')
  145. group = models.CharField(_("Product group/tab"), max_length=128, blank=True, null=True)
  146. def __unicode__(self):
  147. return u"%s - %s (%s)" % (self.block, self.product, self.group)
  148. class Meta:
  149. ordering = ('group',)
  150. class LinkedMerchanisingBlock(models.Model):
  151. block = models.ForeignKey('promotions.MerchandisingBlock')
  152. display_order = models.PositiveIntegerField(default=0)
  153. date_created = models.DateTimeField(auto_now_add=True)
  154. class Meta:
  155. abstract = True
  156. class AbstractPageMerchandisingBlock(LinkedMerchanisingBlock):
  157. u"""
  158. A promotion embedded on a particular page.
  159. """
  160. page_url = ExtendedURLField(max_length=128, db_index=True)
  161. class Meta:
  162. abstract = True
  163. def __unicode__(self):
  164. return u"%s on %s" % (self.block, self.page_url)
  165. class AbstractKeywordMerchandisingBlock(LinkedMerchanisingBlock):
  166. u"""
  167. A promotion linked to a specific keyword.
  168. This can be used on a search results page to show promotions
  169. linked to a particular keyword.
  170. """
  171. keyword = models.CharField(_("Keyword"), max_length=200)
  172. class Meta:
  173. abstract = True