models.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import logging
  2. import dateutil
  3. import os
  4. import re
  5. from datetime import datetime, timedelta
  6. from BeautifulSoup import BeautifulStoneSoup, BeautifulSoup
  7. from django.conf import settings
  8. from django.utils.html import strip_tags
  9. from django.db import models
  10. from django.db.models import permalink
  11. from django.utils.translation import ugettext_lazy as _
  12. from django.core.urlresolvers import reverse
  13. from django.contrib.auth.models import User
  14. import urllib
  15. #from darkroom.models import ImageModel
  16. from classifieds.managers import LiveManager, FeaturedManager
  17. from django_extensions.db.models import TimeStampedModel
  18. class Category(models.Model):
  19. """Category model."""
  20. name=models.CharField(_('name'), max_length=100)
  21. slug=models.SlugField(_('slug'), unique=True)
  22. class Meta:
  23. verbose_name=_('Category')
  24. verbose_name_plural=_('Categories')
  25. ordering=['name']
  26. def __unicode__(self):
  27. return self.name
  28. @models.permalink
  29. def get_absolute_url(self):
  30. return ('category_detail', (), {'slug': self.slug})
  31. class Subcategory(models.Model):
  32. '''Subcategory model.
  33. Really simple, just holds subcats for classified ads.
  34. For this app, objects only interact with subcats, not categories.
  35. '''
  36. name=models.CharField(_('Name'), max_length=100)
  37. number=models.IntegerField(_('Number'), max_length=4, blank=True, null=True)
  38. parent=models.ForeignKey(Category)
  39. slug=models.SlugField(_('slug'), unique=True)
  40. class Meta:
  41. verbose_name=_('Subcategory')
  42. verbose_name_plural=_('Subcategories')
  43. ordering=['parent', 'name']
  44. @property
  45. def active_ads(self):
  46. return self.classified_set.filter(expires_on__gte=datetime.now())
  47. def __unicode__(self):
  48. return self.name
  49. @models.permalink
  50. def get_absolute_url(self):
  51. return ('cl-subcategory-detail', (), {'slug': self.slug})
  52. '''
  53. class ClassifiedPhoto(ImageModel):
  54. image = models.ImageField(_('image'), upload_to='classifieds/images/')
  55. owner = models.ForeignKey(User)
  56. primary=models.BooleanField(_('primary'), default=False, help_text="Set this if you'd like the photo to appear on the main page when this ad is fetaured")
  57. def __unicode__(self):
  58. return self.title
  59. '''
  60. class Classified(TimeStampedModel):
  61. """Classified model."""
  62. STATUS_CHOICES=(
  63. (0, 'Standard'),
  64. (1, 'Plus'),
  65. )
  66. title=models.CharField(_('Title'), max_length=255, blank=True, null=True)
  67. #owner=models.ForeignKey(User, related_name='classifieds')
  68. copy=models.TextField(_('Copy'))
  69. #price=models.IntegerField(_('price'), null=True, blank=True)
  70. #photos = models.ManyToManyField(ClassifiedPhoto, blank=True)
  71. subcategory=models.ForeignKey(Subcategory)
  72. expires_on=models.DateField(_('Expires on'), default=(datetime.now()+timedelta(days=settings.CLASSIFIED_LENGTH)).date())
  73. #featured_until=models.DateField(_('featured until'), null=True, blank=True)
  74. featured=models.BooleanField(_('featured'), default=False)
  75. #status=models.IntegerField(_('status'), choices=STATUS_CHOICES,default=0)
  76. objects=models.Manager()
  77. live_objects=LiveManager()
  78. featured_objects=FeaturedManager()
  79. class Meta:
  80. verbose_name = _('classified')
  81. verbose_name_plural = _('classifieds')
  82. ordering = ('title',)
  83. get_latest_by='created'
  84. def __unicode__(self):
  85. if self.title:
  86. return u'%s' % (self.title)
  87. else:
  88. return u'%s' % (self.copy[0:30])
  89. class ClassifiedsUpload(models.Model):
  90. xml_file = models.FileField(_('xml file'), upload_to="temp",
  91. help_text=_('Select an xml (csv) exported ads file.'), blank=True, null=True)
  92. html_file = models.FileField(_('html file'), upload_to="temp",
  93. help_text=_('Select an html exported ads file.'), blank=True, null=True)
  94. class Meta:
  95. verbose_name = _('classifieds upload')
  96. verbose_name_plural = _('classifieds uploads')
  97. def save(self):
  98. super(ClassifiedsUpload, self).save()
  99. if self.xml_file:
  100. self.process_xmlfile()
  101. elif self.html_file:
  102. self.process_htmlfile()
  103. else:
  104. pass
  105. super(ClassifiedsUpload, self).delete()
  106. def process_xmlfile(self):
  107. xml = open(self.xml_file.path)
  108. soup = BeautifulStoneSoup(xml)
  109. n=0
  110. subcat=Subcategory.objects.get(name="Unclassified")
  111. for tag in soup.findAll('begad'):
  112. if n==0:
  113. pass
  114. else:
  115. next_week=datetime.now()+timedelta(days=7)
  116. ad = Classified(copy=unicode(tag.next), subcategory=subcat, expires_on=next_week)
  117. try:
  118. number=re.match('\<class:\d\d\d\>', str(tag.endad()[0])).group(0)[7:10]
  119. subcat=Subcategory.objects.get(number=int(number))
  120. except:
  121. pass
  122. ad.save()
  123. n+=1
  124. xml.close()
  125. def process_htmlfile(self):
  126. html = open(self.html_file.path)
  127. soup = BeautifulSoup(html)
  128. subcat = Subcategory.objects.get(number=999)
  129. next_week=datetime.now()+timedelta(days=8)
  130. for tag in soup.findAll('td'):
  131. try:
  132. if tag.attrs[0][1] == 'center':
  133. try:
  134. subcat = Subcategory.objects.get(number=int(tag.h2.string[:3]))
  135. except:
  136. subcat = Subcategory.objects.get(name="Unclassified")
  137. elif tag.attrs[0][1]=='left':
  138. copy=''
  139. for item in tag.contents:
  140. copy+=str(item)
  141. ad = Classified(copy=strip_tags(copy), subcategory=subcat, expires_on=next_week)
  142. ad.save()
  143. else:
  144. logging.info("Something went wrong while importing the following classified: %s" % strip_tags(copy))
  145. except:
  146. pass
  147. html.close()