From acfaf3460905054249509f9459a235d99a24f028 Mon Sep 17 00:00:00 2001 From: bnewbold Date: Mon, 19 Feb 2007 00:28:16 -0800 Subject: forgot to add several photo files --- bn_django/photos/models.py | 283 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 bn_django/photos/models.py (limited to 'bn_django/photos/models.py') diff --git a/bn_django/photos/models.py b/bn_django/photos/models.py new file mode 100644 index 0000000..33b2e0a --- /dev/null +++ b/bn_django/photos/models.py @@ -0,0 +1,283 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ +import django.contrib.auth.models as auth +from django.conf import settings +from django.dispatch import dispatcher +from django.db.models import signals + +import os, os.path +import Image + +# Handle settings here +try: + STOCKPHOTO_BASE = settings.STOCKPHOTO_BASE.strip('/') +except AttributeError: + STOCKPHOTO_BASE='photos' + +try: + STOCKPHOTO_URL = settings.STOCKPHOTO_URL +except AttributeError: + STOCKPHOTO_URL='/photos' +if STOCKPHOTO_URL[-1] == '/': + STOCKPHOTO_URL=STOCKPHOTO_URL[:-1] + +try: + ADMIN_URL = settings.ADMIN_URL +except AttributeError: + ADMIN_URL='/admin' +if ADMIN_URL[-1] == '/': + ADMIN_URL=ADMIN_URL[:-1] + +# Create your models here. +class Gallery(models.Model): + title = models.CharField(_("title"), maxlength=80) + slug = models.SlugField(prepopulate_from=("title",)) + date = models.DateField(_("publication date"), auto_now_add=True) + created = models.ForeignKey(auth.User, + verbose_name=_("gallery created by") + ) + display_width = models.IntegerField( + _("width to display full images"), + default=640) + display_height = models.IntegerField( + _("height to display full images"), + default=480) + thumbnail_width = models.IntegerField( + _("width to display thumbnails"), + default=150) + thumbnail_height = models.IntegerField( + _("height to display thumbnails"), + default=100) + + class Meta: + get_latest_by = 'date' + + class Admin: + ordering = ['date'] + + def __str__(self): + return self.title + def get_absolute_url(self): + return "%s/%d/" % (STOCKPHOTO_URL, self.id) + def get_admin_url(self): + return "%s/photos/gallery/%d/" % (ADMIN_URL, self.id) + def was_published_today(self): + return self.date.date() == datetime.date.today() + + def first(self): + try: + return self.photo_set.all()[0] + except IndexError: + return None + def update_thumbs(self): + for photo in self.photo_set.all(): + photo.create_disp() + photo.create_thumb() + +class Photo(models.Model): + # import os, os.path, Image + image = models.ImageField(_("Photograph"), + upload_to= STOCKPHOTO_BASE + "/%Y/%m/%d/") + title = models.CharField(_("title"), maxlength=80) + desc = models.TextField(_("description"), blank=True) + gallery = models.ForeignKey(Gallery) + photographer = models.CharField(_("photographer"), maxlength=80, + blank=True) + date = models.DateField(_("date photographed"), blank=True, null=True) + extra = models.TextField(_("any extra information about the photo"), + blank=True) + class META: + get_latest_by = ['date'] + + class Admin: + ordering = ['date'] + + def __str__(self): + return self.title + + def delete_thumbnails(self): + """Remove thumbnail and display-sized images when deleting. + + This may fail if, for example, they don't exist, so it should + fail silently. It may not be a good idea to delete the + original, as the user may not understand that deleting it from + the gallery deletes it from the filesystem, so currently we + don't do that. + + """ + try: + os.unlink(self.thumbpath()) + except (IOError, OSError): + pass + try: + os.unlink(self.disppath()) + except (IOError, OSError): + pass + # Deleting the original might be a bad thing. + #os.unlink(self.fullpath()) + + def get_absolute_url(self): + return "%s/detail/%d/" % (STOCKPHOTO_URL, self.id) + + def get_admin_url(self): + return "%s/photos/photos/%d/" % (ADMIN_URL, self.id) + + def thumbpath(self): + """Path to the thumbnail + """ + photobase = self.image[len(STOCKPHOTO_BASE)+1:] + return os.path.join( settings.MEDIA_ROOT, STOCKPHOTO_BASE, + "cache", "thumbs", photobase) + + def thumburl(self): + """URL to the thumbnail + """ + photobase = self.image[len(STOCKPHOTO_BASE)+1:] + if settings.MEDIA_URL.endswith('/'): + return settings.MEDIA_URL + STOCKPHOTO_BASE + \ + "/cache/thumbs/" + photobase + return settings.MEDIA_URL + '/' + STOCKPHOTO_BASE + \ + "/cache/thumbs/" + photobase + + + def disppath(self): + photobase = self.image[len(STOCKPHOTO_BASE)+1:] + return os.path.join( settings.MEDIA_ROOT, STOCKPHOTO_BASE, + "cache", photobase) + + def dispurl(self): + photobase = self.image[len(STOCKPHOTO_BASE)+1:] + if settings.MEDIA_URL.endswith('/'): + return settings.MEDIA_URL + STOCKPHOTO_BASE + "/cache/" \ + + photobase + return settings.MEDIA_URL + '/' + STOCKPHOTO_BASE + \ + "/cache/" + photobase + + def fullpath(self): + if self.image.startswith(os.path.sep): + return self.image + return os.path.join(settings.MEDIA_ROOT, self.image) + + def fullurl(self): + if self.image.startswith(os.path.sep): + # Shouldn't happen anymore + return (settings.MEDIA_URL + + self.image[len(settings.MEDIA_ROOT):]) + else: + if settings.MEDIA_URL.endswith('/'): + return settings.MEDIA_URL + self.image + return settings.MEDIA_URL + '/' + self.image + + + def next(self): + '''Return id of 'next' photo in the same gallery or None if at + the end.''' + # we could probably be more clever here by using the new nifty + # db access filters and queries, but for now, this is good enough + photo_list = [x for x in self.gallery.photo_set.all()] + ind = photo_list.index(self) + if (ind +1) == len(photo_list): + return None + else: + return photo_list[ind + 1] + + def prev(self): + """Return id of 'previous' photo in the same gallery or None + if at the beginning + """ + photo_list = [x for x in self.gallery.photo_set.all()] + ind = photo_list.index(self) + if ind == 0: + return False + else: + return photo_list[ind - 1] + + def full_exists(self): + return os.path.exists( self.fullpath() ) + + def disp_exists(self): + return os.path.exists( self.disppath() ) + + def thumb_exists(self): + return os.path.exists( self.thumbpath() ) + + def create_disp(self): + im = Image.open( self.fullpath() ) + format = im.format + # create the path for the display image + disp_path = self.disppath() + disp_dir = os.path.dirname(disp_path) + if not os.path.exists(disp_dir): + os.makedirs(disp_dir, 0775) + + # Make a copy of the image, scaled, if needed. + maxwidth = self.gallery.display_width + maxheight = self.gallery.display_height + width, height = im.size + if (width > maxwidth) and width > height: + scale = float(maxwidth)/width + width = int(width * scale) + height = int(height * scale) + newim = im.resize( (width, height), Image.ANTIALIAS ) + elif (height > maxheight) and height >= width: + scale = float(maxheight)/height + width = int(width * scale) + height = int(height * scale) + newim = im.resize( (width, height), Image.ANTIALIAS ) + else: + newim = im + newim.save(disp_path, format) + + def create_thumb(self): + im = Image.open( self.fullpath() ) + format = im.format + # create the path for the thumbnail image + thumb_path = self.thumbpath() + thumb_dir = os.path.dirname(thumb_path) + if not os.path.exists(thumb_dir): + os.makedirs(thumb_dir, 0775) + + # Make a copy of the image, scaled, if needed. + maxwidth = self.gallery.thumbnail_width + maxheight = self.gallery.thumbnail_height + width, height = im.size + if (width > maxwidth) and (width > height): + scale = float(maxwidth)/width + width = int(width * scale) + height = int(height * scale) + newim = im.resize( (width, height), Image.ANTIALIAS ) + elif (height > maxheight): + scale = float(maxheight)/height + width = int(width * scale) + height = int(height * scale) + newim = im.resize( (width, height), Image.ANTIALIAS ) + else: + newim = im + newim.save(thumb_path, format) + + def build_display_images(self): + """Make thumbnail and display-sized images after saving. + + For some reason, this may fail on a first pass (self.image may + be empty when this is called), but if we just let it fail + silently, it will apparently get called again and succeed. + """ + if self.image: + if not self.thumb_exists(): + self.create_thumb() + if not self.disp_exists(): + self.create_disp() + +def build_display_images(sender, instance, signal, *args, **kwargs): + """Simple hook for save-after trigger + """ + instance.build_display_images() +def delete_thumbnails(sender, instance, signal, *args, **kwargs): + """Simple hook for pre-delete trigger. + """ + instance.delete_thumbnails() + +dispatcher.connect(build_display_images, signal=signals.post_save, + sender=Photo) +dispatcher.connect(delete_thumbnails, signal=signals.pre_delete, + sender=Photo) -- cgit v1.2.3