gremmie@1: """ gremmie@1: Models for the Photo Of The Day (POTD) application. bgneal@515: gremmie@1: """ gremmie@1: import os gremmie@1: from PIL import ImageFile gremmie@1: from PIL import Image gremmie@1: try: gremmie@1: from cStringIO import StringIO gremmie@1: except: gremmie@1: from StringIO import StringIO gremmie@1: gremmie@1: from django.db import models gremmie@1: from django.contrib.auth.models import User gremmie@1: from django.core.files.base import ContentFile gremmie@1: gremmie@1: POTD_THUMB_WIDTH = 120 gremmie@1: gremmie@1: def scale_image(image): gremmie@1: (w, h) = image.size gremmie@1: if w <= POTD_THUMB_WIDTH: gremmie@1: return image gremmie@1: scale_factor = float(POTD_THUMB_WIDTH) / w gremmie@1: new_height = int(scale_factor * h) gremmie@1: return image.resize((POTD_THUMB_WIDTH, new_height), Image.ANTIALIAS) gremmie@1: gremmie@1: gremmie@1: class Photo(models.Model): gremmie@1: """Model to represent a POTD""" gremmie@1: photo = models.ImageField(upload_to='potd/%Y/%m/%d') gremmie@1: thumb = models.ImageField(upload_to='potd/%Y/%m/%d/thumbs', blank=True, null=True) gremmie@1: caption = models.CharField(max_length=128) gremmie@1: description = models.TextField() gremmie@1: user = models.ForeignKey(User) gremmie@1: date_added = models.DateField(auto_now_add=True) gremmie@1: potd_count = models.IntegerField(default=0) gremmie@1: bgneal@14: class Meta: bgneal@14: ordering = ('-date_added', '-caption') bgneal@14: gremmie@1: def __unicode__(self): gremmie@1: return u'%s (%s)' % (self.caption, self.pk) gremmie@1: bgneal@14: @models.permalink bgneal@14: def get_absolute_url(self): bgneal@14: return ('potd-archive', [str(self.id)]) gremmie@1: bgneal@182: def save(self, *args, **kwargs): bgneal@330: if not self.pk: bgneal@330: self.generate_thumb() gremmie@1: bgneal@330: super(Photo, self).save(*args, **kwargs) bgneal@330: Sequence.objects.insert_photo(self.pk) bgneal@330: bgneal@330: def delete(self): bgneal@330: Sequence.objects.remove_photo(self.pk) bgneal@330: super(Photo, self).delete() bgneal@330: bgneal@330: def can_comment_on(self): bgneal@330: return Current.objects.get_current_id() == self.id bgneal@330: bgneal@330: def generate_thumb(self): gremmie@1: if self.thumb: gremmie@1: self.thumb.delete(save=False) gremmie@1: gremmie@1: parser = ImageFile.Parser() gremmie@1: for chunk in self.photo.chunks(): gremmie@1: parser.feed(chunk) gremmie@1: image = parser.close() gremmie@1: format = image.format gremmie@1: image = scale_image(image) gremmie@1: s = StringIO() gremmie@1: image.save(s, format) gremmie@1: thumb_name = os.path.basename(self.photo.path) gremmie@1: self.thumb.save(thumb_name, ContentFile(s.getvalue()), save=False) gremmie@1: bgneal@491: def ogp_tags(self): bgneal@491: """ bgneal@491: Returns a dict of Open Graph Protocol meta tags. bgneal@491: bgneal@491: """ bgneal@491: desc = "Photo of the day: %s." % self.caption bgneal@491: return { bgneal@491: 'og:title': self.caption, bgneal@491: 'og:type': 'article', bgneal@491: 'og:url': self.get_absolute_url(), bgneal@491: 'og:image': self.photo.url, bgneal@491: 'og:description': desc, bgneal@491: } bgneal@491: gremmie@1: gremmie@1: class CurrentManager(models.Manager): bgneal@515: """ bgneal@515: Manager for the Current model. bgneal@515: bgneal@515: """ gremmie@1: def get_current_photo(self): bgneal@515: """ bgneal@515: Retrieves the current photo object from the current record. bgneal@515: bgneal@515: """ gremmie@1: try: gremmie@1: c = self.get(pk=1) gremmie@1: return c.potd gremmie@1: except Current.DoesNotExist: gremmie@1: return None gremmie@1: gremmie@1: def get_current_id(self): bgneal@515: """ bgneal@515: Returns the ID of the current POTD from the current record. bgneal@515: bgneal@515: """ gremmie@1: potd = self.get_current_photo() gremmie@1: if potd is not None: gremmie@1: return potd.pk gremmie@1: return None gremmie@1: gremmie@1: gremmie@1: class Current(models.Model): gremmie@1: """This model simply stores the current POTD.""" gremmie@1: potd = models.ForeignKey(Photo) gremmie@1: gremmie@1: objects = CurrentManager() gremmie@1: gremmie@1: def __unicode__(self): gremmie@1: return self.potd.__unicode__() gremmie@1: gremmie@1: class Meta: gremmie@1: verbose_name_plural = 'Current' gremmie@1: gremmie@1: gremmie@1: class SequenceManager(models.Manager): bgneal@515: """ bgneal@515: Manager for the Sequence model. bgneal@515: bgneal@515: """ gremmie@1: def insert_photo(self, photo_id): bgneal@515: """ bgneal@515: Inserts the given photo_id just after the current photo so it bgneal@515: will appear as tomorrow's POTD. bgneal@515: bgneal@515: """ gremmie@1: current = Current.objects.get_current_id() gremmie@1: if current is not None: bgneal@330: s = self.get(pk=1) bgneal@330: seq = [int(x) for x in s.seq.split(',')] bgneal@330: if photo_id not in seq: bgneal@330: i = seq.index(current) bgneal@330: seq.insert(i + 1, photo_id) bgneal@330: s.seq = ','.join([str(x) for x in seq]) bgneal@330: s.save() gremmie@1: gremmie@1: def remove_photo(self, photo_id): bgneal@515: """ bgneal@515: Removes a given photo id from the sequence of photos. bgneal@515: bgneal@515: """ gremmie@1: try: gremmie@1: s = self.get(pk=1) bgneal@330: except Sequence.DoesNotExist: bgneal@330: pass bgneal@330: else: gremmie@1: seq = [int(x) for x in s.seq.split(',')] gremmie@1: if photo_id in seq: gremmie@1: seq.remove(photo_id) gremmie@1: s.seq = ','.join([str(x) for x in seq]) gremmie@1: s.save() gremmie@1: gremmie@1: gremmie@1: class Sequence(models.Model): gremmie@1: """This model stores the sequence of photos for the POTD.""" gremmie@1: seq = models.CommaSeparatedIntegerField(max_length=4096) gremmie@1: gremmie@1: objects = SequenceManager() gremmie@1: gremmie@1: def __unicode__(self): gremmie@1: return self.seq gremmie@1: gremmie@1: class Meta: gremmie@1: verbose_name_plural = 'Sequence' gremmie@1: