You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

models.py 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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.contrib.contenttypes.models import ContentType
  6. from django.contrib.contenttypes import generic
  7. from django.db.models import get_model
  8. from oscar.models.fields import ExtendedURLField
  9. Item = get_model('product', 'Item')
  10. # Linking models
  11. class LinkedPromotion(models.Model):
  12. # We use generic foreign key to link to a promotion model
  13. content_type = models.ForeignKey(ContentType)
  14. object_id = models.PositiveIntegerField()
  15. content_object = generic.GenericForeignKey('content_type', 'object_id')
  16. position = models.CharField(_("Position"), max_length=100, help_text="Position on page")
  17. display_order = models.PositiveIntegerField(default=0)
  18. clicks = models.PositiveIntegerField(default=0)
  19. date_created = models.DateTimeField(auto_now_add=True)
  20. class Meta:
  21. abstract = True
  22. ordering = ['-clicks']
  23. def record_click(self):
  24. self.clicks += 1
  25. self.save()
  26. class PagePromotion(LinkedPromotion):
  27. """
  28. A promotion embedded on a particular page.
  29. """
  30. page_url = ExtendedURLField(max_length=128, db_index=True)
  31. def __unicode__(self):
  32. return u"%s on %s" % (self.content_object, self.page_url)
  33. def get_link(self):
  34. return reverse('promotions:page-click', kwargs={'page_promotion_id': self.id})
  35. class KeywordPromotion(LinkedPromotion):
  36. """
  37. A promotion linked to a specific keyword.
  38. This can be used on a search results page to show promotions
  39. linked to a particular keyword.
  40. """
  41. keyword = models.CharField(_("Keyword"), max_length=200)
  42. # We allow an additional filter which will let search query matches
  43. # be restricted to different parts of the site.
  44. filter = models.CharField(_("Filter"), max_length=200, blank=True, null=True)
  45. def get_link(self):
  46. return reverse('promotions:keyword-click', kwargs={'keyword_promotion_id': self.id})
  47. # Different model types for each type of promotion
  48. class AbstractPromotion(models.Model):
  49. """
  50. Abstract base promotion that defines the interface
  51. that subclasses must implement.
  52. """
  53. _type = 'Promotion'
  54. class Meta:
  55. abstract = True
  56. @property
  57. def type(self):
  58. return _(self._type)
  59. def template_name(self):
  60. """
  61. Returns the template to use to render this
  62. promotion.
  63. """
  64. return 'promotions/%s.html' % self.__class__.__name__.lower()
  65. def template_context(self, *args, **kwargs):
  66. return {}
  67. @property
  68. def content_type(self):
  69. return ContentType.objects.get_for_model(self)
  70. @property
  71. def num_times_used(self):
  72. ctype = self.content_type
  73. page_count = PagePromotion.objects.filter(content_type=ctype,
  74. object_id=self.id).count()
  75. keyword_count = KeywordPromotion.objects.filter(content_type=ctype,
  76. object_id=self.id).count()
  77. return page_count + keyword_count
  78. class RawHTML(AbstractPromotion):
  79. """
  80. Simple promotion - just raw HTML
  81. """
  82. _type = 'Raw HTML'
  83. name = models.CharField(_("Name"), max_length=128)
  84. body = models.TextField(_("HTML"))
  85. date_created = models.DateTimeField(auto_now_add=True)
  86. class Meta:
  87. verbose_name_plural = 'Raw HTML'
  88. def __unicode__(self):
  89. return self.name
  90. class Image(AbstractPromotion):
  91. """
  92. An image promotion is simply a named image which has an optional
  93. link to another part of the site (or another site).
  94. This can be used to model both banners and pods.
  95. """
  96. _type = 'Image'
  97. name = models.CharField(_("Name"), max_length=128)
  98. link_url = ExtendedURLField(blank=True, null=True, help_text="""This is
  99. where this promotion links to""")
  100. image = models.ImageField(upload_to=settings.OSCAR_PROMOTION_FOLDER, blank=True, null=True)
  101. date_created = models.DateTimeField(auto_now_add=True)
  102. def __unicode__(self):
  103. return self.name
  104. class MultiImage(AbstractPromotion):
  105. """
  106. A multi-image promotion is simply a collection of image promotions
  107. that are rendered in a specific way. This models things like
  108. rotating banners.
  109. """
  110. _type = 'Multi-image'
  111. name = models.CharField(_("Name"), max_length=128)
  112. images = models.ManyToManyField('promotions.Image', null=True, blank=True)
  113. date_created = models.DateTimeField(auto_now_add=True)
  114. def __unicode__(self):
  115. return self.name
  116. class SingleProduct(AbstractPromotion):
  117. _type = 'Single product'
  118. name = models.CharField(_("Name"), max_length=128)
  119. product = models.ForeignKey('catalogue.Product')
  120. description = models.TextField(_("Description"), null=True, blank=True)
  121. date_created = models.DateTimeField(auto_now_add=True)
  122. def __unicode__(self):
  123. return self.name
  124. class AbstractProductList(AbstractPromotion):
  125. """
  126. Abstract superclass for promotions which are essentially a list
  127. of products.
  128. """
  129. name = models.CharField(_("Title"), max_length=255)
  130. description = models.TextField(null=True, blank=True)
  131. link_url = ExtendedURLField(blank=True, null=True)
  132. date_created = models.DateTimeField(auto_now_add=True)
  133. class Meta:
  134. abstract = True
  135. def __unicode__(self):
  136. return self.name
  137. class HandPickedProductList(AbstractProductList):
  138. """
  139. A hand-picked product list is a list of manually selected
  140. products.
  141. """
  142. _type = 'Product list'
  143. products = models.ManyToManyField('catalogue.Product', through='OrderedProduct', blank=True, null=True)
  144. class OrderedProduct(models.Model):
  145. list = models.ForeignKey('promotions.HandPickedProductList')
  146. product = models.ForeignKey('catalogue.Product')
  147. display_order = models.PositiveIntegerField(default=0)
  148. class Meta:
  149. ordering = ('display_order',)
  150. class AutomaticProductList(AbstractProductList):
  151. _type = 'Auto-product list'
  152. BESTSELLING, RECENTLY_ADDED = ('Bestselling', 'RecentlyAdded')
  153. METHOD_CHOICES = (
  154. (BESTSELLING, _("Bestselling products")),
  155. (RECENTLY_ADDED, _("Recently added products")),
  156. )
  157. method = models.CharField(max_length=128, choices=METHOD_CHOICES)
  158. num_products = models.PositiveSmallIntegerField(default=4)
  159. def get_products(self):
  160. if self.method == self.BESTSELLING:
  161. return Product.objects.all().order_by('-score')[:self.num_products]
  162. return Product.objects.all().order_by('-date_created')[:self.num_products]
  163. class OrderedProductList(models.Model):
  164. tabbed_block = models.ForeignKey('promotions.TabbedBlock')
  165. list = models.ForeignKey('promotions.HandPickedProductList')
  166. display_order = models.PositiveIntegerField(default=0)
  167. class Meta:
  168. ordering = ('display_order',)
  169. class TabbedBlock(AbstractPromotion):
  170. _type = 'Tabbed block'
  171. name = models.CharField(_("Title"), max_length=255)
  172. tabs = models.ManyToManyField('promotions.HandPickedProductList', through='OrderedProductList', null=True, blank=True)
  173. date_created = models.DateTimeField(auto_now_add=True)