web/lib/photologue/models.py
author ymh <ymh.work@gmail.com>
Thu, 21 Jan 2010 18:41:10 +0100
changeset 5 10b1f6d8a5d2
permissions -rw-r--r--
first debug version
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
5
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     1
import os
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     2
import random
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     3
import shutil
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     4
import zipfile
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
from datetime import datetime
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     7
from inspect import isclass
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     8
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
from django.db import models
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    10
from django.db.models.signals import post_init
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    11
from django.conf import settings
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    12
from django.core.files.base import ContentFile
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    13
from django.core.urlresolvers import reverse
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    14
from django.template.defaultfilters import slugify
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    15
from django.utils.functional import curry
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    16
from django.utils.translation import ugettext_lazy as _
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    17
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    18
# Required PIL classes may or may not be available from the root namespace
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    19
# depending on the installation method used.
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    20
try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    21
    import Image
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    22
    import ImageFile
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    23
    import ImageFilter
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    24
    import ImageEnhance
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    25
except ImportError:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    26
    try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    27
        from PIL import Image
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    28
        from PIL import ImageFile
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    29
        from PIL import ImageFilter
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    30
        from PIL import ImageEnhance
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    31
    except ImportError:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    32
        raise ImportError('Photologue was unable to import the Python Imaging Library. Please confirm it`s installed and available on your current Python path.')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    33
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    34
# attempt to load the django-tagging TagField from default location,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    35
# otherwise we substitude a dummy TagField.
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    36
try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    37
    from tagging.fields import TagField
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    38
    tagfield_help_text = _('Separate tags with spaces, put quotes around multiple-word tags.')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    39
except ImportError:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    40
    class TagField(models.CharField):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    41
        def __init__(self, **kwargs):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    42
            default_kwargs = {'max_length': 255, 'blank': True}
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    43
            default_kwargs.update(kwargs)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    44
            super(TagField, self).__init__(**default_kwargs)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    45
        def get_internal_type(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    46
            return 'CharField'
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    47
    tagfield_help_text = _('Django-tagging was not found, tags will be treated as plain text.')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    48
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    49
from utils import EXIF
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    50
from utils.reflection import add_reflection
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    51
from utils.watermark import apply_watermark
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    52
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    53
# Path to sample image
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    54
SAMPLE_IMAGE_PATH = getattr(settings, 'SAMPLE_IMAGE_PATH', os.path.join(os.path.dirname(__file__), 'res', 'sample.jpg')) # os.path.join(settings.PROJECT_PATH, 'photologue', 'res', 'sample.jpg'
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    55
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    56
# Modify image file buffer size.
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    57
ImageFile.MAXBLOCK = getattr(settings, 'PHOTOLOGUE_MAXBLOCK', 256 * 2 ** 10)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    58
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    59
# Photologue image path relative to media root
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    60
PHOTOLOGUE_DIR = getattr(settings, 'PHOTOLOGUE_DIR', 'photologue')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    61
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    62
# Look for user function to define file paths
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    63
PHOTOLOGUE_PATH = getattr(settings, 'PHOTOLOGUE_PATH', None)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    64
if PHOTOLOGUE_PATH is not None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    65
    if callable(PHOTOLOGUE_PATH):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    66
        get_storage_path = PHOTOLOGUE_PATH
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    67
    else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    68
        parts = PHOTOLOGUE_PATH.split('.')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    69
        module_name = '.'.join(parts[:-1])
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    70
        module = __import__(module_name)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    71
        get_storage_path = getattr(module, parts[-1])
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    72
else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    73
    def get_storage_path(instance, filename):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    74
        return os.path.join(PHOTOLOGUE_DIR, 'photos', filename)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    75
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    76
# Quality options for JPEG images
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    77
JPEG_QUALITY_CHOICES = (
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    78
    (30, _('Very Low')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    79
    (40, _('Low')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    80
    (50, _('Medium-Low')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    81
    (60, _('Medium')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    82
    (70, _('Medium-High')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    83
    (80, _('High')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    84
    (90, _('Very High')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    85
)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    86
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    87
# choices for new crop_anchor field in Photo
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    88
CROP_ANCHOR_CHOICES = (
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    89
    ('top', _('Top')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    90
    ('right', _('Right')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    91
    ('bottom', _('Bottom')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    92
    ('left', _('Left')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    93
    ('center', _('Center (Default)')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    94
)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    95
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    96
IMAGE_TRANSPOSE_CHOICES = (
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    97
    ('FLIP_LEFT_RIGHT', _('Flip left to right')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    98
    ('FLIP_TOP_BOTTOM', _('Flip top to bottom')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    99
    ('ROTATE_90', _('Rotate 90 degrees counter-clockwise')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   100
    ('ROTATE_270', _('Rotate 90 degrees clockwise')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   101
    ('ROTATE_180', _('Rotate 180 degrees')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   102
)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   103
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   104
WATERMARK_STYLE_CHOICES = (
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   105
    ('tile', _('Tile')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   106
    ('scale', _('Scale')),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   107
)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   108
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   109
# Prepare a list of image filters
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   110
filter_names = []
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   111
for n in dir(ImageFilter):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   112
    klass = getattr(ImageFilter, n)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   113
    if isclass(klass) and issubclass(klass, ImageFilter.BuiltinFilter) and \
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   114
        hasattr(klass, 'name'):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   115
            filter_names.append(klass.__name__)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   116
IMAGE_FILTERS_HELP_TEXT = _('Chain multiple filters using the following pattern "FILTER_ONE->FILTER_TWO->FILTER_THREE". Image filters will be applied in order. The following filters are available: %s.' % (', '.join(filter_names)))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   117
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   118
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   119
class Gallery(models.Model):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   120
    date_added = models.DateTimeField(_('date published'), default=datetime.now)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   121
    title = models.CharField(_('title'), max_length=100, unique=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   122
    title_slug = models.SlugField(_('title slug'), unique=True,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   123
                                  help_text=_('A "slug" is a unique URL-friendly title for an object.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   124
    description = models.TextField(_('description'), blank=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   125
    is_public = models.BooleanField(_('is public'), default=True,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   126
                                    help_text=_('Public galleries will be displayed in the default views.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   127
    photos = models.ManyToManyField('Photo', related_name='galleries', verbose_name=_('photos'),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   128
                                    null=True, blank=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   129
    tags = TagField(help_text=tagfield_help_text, verbose_name=_('tags'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   130
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   131
    class Meta:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   132
        ordering = ['-date_added']
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   133
        get_latest_by = 'date_added'
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   134
        verbose_name = _('gallery')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   135
        verbose_name_plural = _('galleries')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   136
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   137
    def __unicode__(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   138
        return self.title
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   139
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   140
    def __str__(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   141
        return self.__unicode__()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   142
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   143
    def get_absolute_url(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   144
        return reverse('pl-gallery', args=[self.title_slug])
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   145
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   146
    def latest(self, limit=0, public=True):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   147
        if limit == 0:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   148
            limit = self.photo_count()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   149
        if public:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   150
            return self.public()[:limit]
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   151
        else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   152
            return self.photos.all()[:limit]
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   153
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   154
    def sample(self, count=0, public=True):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   155
        if count == 0 or count > self.photo_count():
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   156
            count = self.photo_count()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   157
        if public:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   158
            photo_set = self.public()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   159
        else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   160
            photo_set = self.photos.all()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   161
        return random.sample(photo_set, count)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   162
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   163
    def photo_count(self, public=True):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   164
        if public:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   165
            return self.public().count()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   166
        else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   167
            return self.photos.all().count()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   168
    photo_count.short_description = _('count')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   169
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   170
    def public(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   171
        return self.photos.filter(is_public=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   172
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   173
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   174
class GalleryUpload(models.Model):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   175
    zip_file = models.FileField(_('images file (.zip)'), upload_to=PHOTOLOGUE_DIR+"/temp",
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   176
                                help_text=_('Select a .zip file of images to upload into a new Gallery.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   177
    gallery = models.ForeignKey(Gallery, null=True, blank=True, help_text=_('Select a gallery to add these images to. leave this empty to create a new gallery from the supplied title.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   178
    title = models.CharField(_('title'), max_length=75, help_text=_('All photos in the gallery will be given a title made up of the gallery title + a sequential number.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   179
    caption = models.TextField(_('caption'), blank=True, help_text=_('Caption will be added to all photos.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   180
    description = models.TextField(_('description'), blank=True, help_text=_('A description of this Gallery.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   181
    is_public = models.BooleanField(_('is public'), default=True, help_text=_('Uncheck this to make the uploaded gallery and included photographs private.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   182
    tags = models.CharField(max_length=255, blank=True, help_text=tagfield_help_text, verbose_name=_('tags'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   183
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   184
    class Meta:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   185
        verbose_name = _('gallery upload')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   186
        verbose_name_plural = _('gallery uploads')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   187
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   188
    def save(self, *args, **kwargs):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   189
        super(GalleryUpload, self).save(*args, **kwargs)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   190
        gallery = self.process_zipfile()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   191
        super(GalleryUpload, self).delete()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   192
        return gallery
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   193
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   194
    def process_zipfile(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   195
        if os.path.isfile(self.zip_file.path):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   196
            # TODO: implement try-except here
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   197
            zip = zipfile.ZipFile(self.zip_file.path)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   198
            bad_file = zip.testzip()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   199
            if bad_file:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   200
                raise Exception('"%s" in the .zip archive is corrupt.' % bad_file)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   201
            count = 1
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   202
            if self.gallery:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   203
                gallery = self.gallery
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   204
            else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   205
                gallery = Gallery.objects.create(title=self.title,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   206
                                                 title_slug=slugify(self.title),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   207
                                                 description=self.description,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   208
                                                 is_public=self.is_public,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   209
                                                 tags=self.tags)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   210
            from cStringIO import StringIO
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   211
            for filename in zip.namelist():
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   212
                if filename.startswith('__'): # do not process meta files
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   213
                    continue
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   214
                data = zip.read(filename)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   215
                if len(data):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   216
                    try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   217
                        # the following is taken from django.newforms.fields.ImageField:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   218
                        #  load() is the only method that can spot a truncated JPEG,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   219
                        #  but it cannot be called sanely after verify()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   220
                        trial_image = Image.open(StringIO(data))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   221
                        trial_image.load()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   222
                        # verify() is the only method that can spot a corrupt PNG,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   223
                        #  but it must be called immediately after the constructor
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   224
                        trial_image = Image.open(StringIO(data))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   225
                        trial_image.verify()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   226
                    except Exception:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   227
                        # if a "bad" file is found we just skip it.
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   228
                        continue
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   229
                    while 1:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   230
                        title = ' '.join([self.title, str(count)])
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   231
                        slug = slugify(title)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   232
                        try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   233
                            p = Photo.objects.get(title_slug=slug)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   234
                        except Photo.DoesNotExist:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   235
                            photo = Photo(title=title,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   236
                                          title_slug=slug,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   237
                                          caption=self.caption,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   238
                                          is_public=self.is_public,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   239
                                          tags=self.tags)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   240
                            photo.image.save(filename, ContentFile(data))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   241
                            gallery.photos.add(photo)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   242
                            count = count + 1
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   243
                            break
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   244
                        count = count + 1
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   245
            zip.close()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   246
            return gallery
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   247
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   248
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   249
class ImageModel(models.Model):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   250
    image = models.ImageField(_('image'), upload_to=get_storage_path)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   251
    date_taken = models.DateTimeField(_('date taken'), null=True, blank=True, editable=False)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   252
    view_count = models.PositiveIntegerField(default=0, editable=False)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   253
    crop_from = models.CharField(_('crop from'), blank=True, max_length=10, default='center', choices=CROP_ANCHOR_CHOICES)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   254
    effect = models.ForeignKey('PhotoEffect', null=True, blank=True, related_name="%(class)s_related", verbose_name=_('effect'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   255
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   256
    class Meta:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   257
        abstract = True
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   258
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   259
    @property
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   260
    def EXIF(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   261
        try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   262
            return EXIF.process_file(open(self.image.path, 'rb'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   263
        except:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   264
            try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   265
                return EXIF.process_file(open(self.image.path, 'rb'), details=False)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   266
            except:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   267
                return {}
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   268
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   269
    def admin_thumbnail(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   270
        func = getattr(self, 'get_admin_thumbnail_url', None)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   271
        if func is None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   272
            return _('An "admin_thumbnail" photo size has not been defined.')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   273
        else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   274
            if hasattr(self, 'get_absolute_url'):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   275
                return u'<a href="%s"><img src="%s"></a>' % \
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   276
                    (self.get_absolute_url(), func())
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   277
            else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   278
                return u'<a href="%s"><img src="%s"></a>' % \
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   279
                    (self.image.url, func())
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   280
    admin_thumbnail.short_description = _('Thumbnail')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   281
    admin_thumbnail.allow_tags = True
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   282
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   283
    def cache_path(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   284
        return os.path.join(os.path.dirname(self.image.path), "cache")
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   285
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   286
    def cache_url(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   287
        return '/'.join([os.path.dirname(self.image.url), "cache"])
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   288
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   289
    def image_filename(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   290
        return os.path.basename(self.image.path)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   291
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   292
    def _get_filename_for_size(self, size):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   293
        size = getattr(size, 'name', size)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   294
        base, ext = os.path.splitext(self.image_filename())
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   295
        return ''.join([base, '_', size, ext])
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   296
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   297
    def _get_SIZE_photosize(self, size):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   298
        return PhotoSizeCache().sizes.get(size)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   299
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   300
    def _get_SIZE_size(self, size):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   301
        photosize = PhotoSizeCache().sizes.get(size)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   302
        if not self.size_exists(photosize):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   303
            self.create_size(photosize)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   304
        return Image.open(self._get_SIZE_filename(size)).size
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   305
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   306
    def _get_SIZE_url(self, size):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   307
        photosize = PhotoSizeCache().sizes.get(size)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   308
        if not self.size_exists(photosize):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   309
            self.create_size(photosize)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   310
        if photosize.increment_count:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   311
            self.increment_count()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   312
        return '/'.join([self.cache_url(), self._get_filename_for_size(photosize.name)])
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   313
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   314
    def _get_SIZE_filename(self, size):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   315
        photosize = PhotoSizeCache().sizes.get(size)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   316
        return os.path.join(self.cache_path(),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   317
                            self._get_filename_for_size(photosize.name))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   318
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   319
    def increment_count(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   320
        self.view_count += 1
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   321
        models.Model.save(self)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   322
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   323
    def add_accessor_methods(self, *args, **kwargs):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   324
        for size in PhotoSizeCache().sizes.keys():
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   325
            setattr(self, 'get_%s_size' % size,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   326
                    curry(self._get_SIZE_size, size=size))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   327
            setattr(self, 'get_%s_photosize' % size,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   328
                    curry(self._get_SIZE_photosize, size=size))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   329
            setattr(self, 'get_%s_url' % size,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   330
                    curry(self._get_SIZE_url, size=size))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   331
            setattr(self, 'get_%s_filename' % size,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   332
                    curry(self._get_SIZE_filename, size=size))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   333
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   334
    def size_exists(self, photosize):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   335
        func = getattr(self, "get_%s_filename" % photosize.name, None)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   336
        if func is not None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   337
            if os.path.isfile(func()):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   338
                return True
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   339
        return False
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   340
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   341
    def resize_image(self, im, photosize):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   342
        cur_width, cur_height = im.size
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   343
        new_width, new_height = photosize.size
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   344
        if photosize.crop:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   345
            ratio = max(float(new_width)/cur_width,float(new_height)/cur_height)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   346
            x = (cur_width * ratio)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   347
            y = (cur_height * ratio)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   348
            xd = abs(new_width - x)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   349
            yd = abs(new_height - y)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   350
            x_diff = int(xd / 2)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   351
            y_diff = int(yd / 2)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   352
            if self.crop_from == 'top':
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   353
                box = (int(x_diff), 0, int(x_diff+new_width), new_height)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   354
            elif self.crop_from == 'left':
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   355
                box = (0, int(y_diff), new_width, int(y_diff+new_height))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   356
            elif self.crop_from == 'bottom':
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   357
                box = (int(x_diff), int(yd), int(x_diff+new_width), int(y)) # y - yd = new_height
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   358
            elif self.crop_from == 'right':
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   359
                box = (int(xd), int(y_diff), int(x), int(y_diff+new_height)) # x - xd = new_width
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   360
            else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   361
                box = (int(x_diff), int(y_diff), int(x_diff+new_width), int(y_diff+new_height))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   362
            im = im.resize((int(x), int(y)), Image.ANTIALIAS).crop(box)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   363
        else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   364
            if not new_width == 0 and not new_height == 0:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   365
                ratio = min(float(new_width)/cur_width,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   366
                            float(new_height)/cur_height)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   367
            else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   368
                if new_width == 0:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   369
                    ratio = float(new_height)/cur_height
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   370
                else:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   371
                    ratio = float(new_width)/cur_width
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   372
            new_dimensions = (int(round(cur_width*ratio)),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   373
                              int(round(cur_height*ratio)))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   374
            if new_dimensions[0] > cur_width or \
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   375
               new_dimensions[1] > cur_height:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   376
                if not photosize.upscale:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   377
                    return im
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   378
            im = im.resize(new_dimensions, Image.ANTIALIAS)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   379
        return im
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   380
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   381
    def create_size(self, photosize):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   382
        if self.size_exists(photosize):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   383
            return
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   384
        if not os.path.isdir(self.cache_path()):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   385
            os.makedirs(self.cache_path())
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   386
        try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   387
            im = Image.open(self.image.path)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   388
        except IOError:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   389
            return
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   390
        # Save the original format
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   391
        im_format = im.format
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   392
        # Apply effect if found
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   393
        if self.effect is not None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   394
            im = self.effect.pre_process(im)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   395
        elif photosize.effect is not None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   396
            im = photosize.effect.pre_process(im)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   397
        # Resize/crop image
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   398
        if im.size != photosize.size and photosize.size != (0, 0):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   399
            im = self.resize_image(im, photosize)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   400
        # Apply watermark if found
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   401
        if photosize.watermark is not None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   402
            im = photosize.watermark.post_process(im)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   403
        # Apply effect if found
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   404
        if self.effect is not None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   405
            im = self.effect.post_process(im)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   406
        elif photosize.effect is not None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   407
            im = photosize.effect.post_process(im)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   408
        # Save file
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   409
        im_filename = getattr(self, "get_%s_filename" % photosize.name)()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   410
        try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   411
            if im_format != 'JPEG':
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   412
                try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   413
                    im.save(im_filename)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   414
                    return
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   415
                except KeyError:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   416
                    pass
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   417
            im.save(im_filename, 'JPEG', quality=int(photosize.quality), optimize=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   418
        except IOError, e:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   419
            if os.path.isfile(im_filename):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   420
                os.unlink(im_filename)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   421
            raise e
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   422
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   423
    def remove_size(self, photosize, remove_dirs=True):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   424
        if not self.size_exists(photosize):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   425
            return
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   426
        filename = getattr(self, "get_%s_filename" % photosize.name)()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   427
        if os.path.isfile(filename):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   428
            os.remove(filename)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   429
        if remove_dirs:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   430
            self.remove_cache_dirs()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   431
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   432
    def clear_cache(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   433
        cache = PhotoSizeCache()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   434
        for photosize in cache.sizes.values():
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   435
            self.remove_size(photosize, False)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   436
        self.remove_cache_dirs()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   437
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   438
    def pre_cache(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   439
        cache = PhotoSizeCache()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   440
        for photosize in cache.sizes.values():
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   441
            if photosize.pre_cache:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   442
                self.create_size(photosize)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   443
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   444
    def remove_cache_dirs(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   445
        try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   446
            os.removedirs(self.cache_path())
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   447
        except:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   448
            pass
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   449
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   450
    def save(self, *args, **kwargs):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   451
        if self.date_taken is None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   452
            try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   453
                exif_date = self.EXIF.get('EXIF DateTimeOriginal', None)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   454
                if exif_date is not None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   455
                    d, t = str.split(exif_date.values)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   456
                    year, month, day = d.split(':')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   457
                    hour, minute, second = t.split(':')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   458
                    self.date_taken = datetime(int(year), int(month), int(day),
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   459
                                               int(hour), int(minute), int(second))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   460
            except:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   461
                pass
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   462
        if self.date_taken is None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   463
            self.date_taken = datetime.now()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   464
        if self._get_pk_val():
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   465
            self.clear_cache()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   466
        super(ImageModel, self).save(*args, **kwargs)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   467
        self.pre_cache()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   468
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   469
    def delete(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   470
        assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   471
        self.clear_cache()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   472
        super(ImageModel, self).delete()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   473
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   474
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   475
class Photo(ImageModel):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   476
    title = models.CharField(_('title'), max_length=100, unique=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   477
    title_slug = models.SlugField(_('slug'), unique=True,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   478
                                  help_text=('A "slug" is a unique URL-friendly title for an object.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   479
    caption = models.TextField(_('caption'), blank=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   480
    date_added = models.DateTimeField(_('date added'), default=datetime.now, editable=False)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   481
    is_public = models.BooleanField(_('is public'), default=True, help_text=_('Public photographs will be displayed in the default views.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   482
    tags = TagField(help_text=tagfield_help_text, verbose_name=_('tags'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   483
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   484
    class Meta:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   485
        ordering = ['-date_added']
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   486
        get_latest_by = 'date_added'
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   487
        verbose_name = _("photo")
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   488
        verbose_name_plural = _("photos")
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   489
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   490
    def __unicode__(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   491
        return self.title
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   492
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   493
    def __str__(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   494
        return self.__unicode__()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   495
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   496
    def save(self, *args, **kwargs):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   497
        if self.title_slug is None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   498
            self.title_slug = slugify(self.title)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   499
        super(Photo, self).save(*args, **kwargs)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   500
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   501
    def get_absolute_url(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   502
        return reverse('pl-photo', args=[self.title_slug])
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   503
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   504
    def public_galleries(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   505
        """Return the public galleries to which this photo belongs."""
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   506
        return self.galleries.filter(is_public=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   507
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   508
    def get_previous_in_gallery(self, gallery):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   509
        try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   510
            return self.get_previous_by_date_added(galleries__exact=gallery,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   511
                                                   is_public=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   512
        except Photo.DoesNotExist:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   513
            return None
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   514
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   515
    def get_next_in_gallery(self, gallery):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   516
        try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   517
            return self.get_next_by_date_added(galleries__exact=gallery,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   518
                                               is_public=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   519
        except Photo.DoesNotExist:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   520
            return None
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   521
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   522
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   523
class BaseEffect(models.Model):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   524
    name = models.CharField(_('name'), max_length=30, unique=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   525
    description = models.TextField(_('description'), blank=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   526
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   527
    class Meta:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   528
        abstract = True
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   529
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   530
    def sample_dir(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   531
        return os.path.join(settings.MEDIA_ROOT, PHOTOLOGUE_DIR, 'samples')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   532
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   533
    def sample_url(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   534
        return settings.MEDIA_URL + '/'.join([PHOTOLOGUE_DIR, 'samples', '%s %s.jpg' % (self.name.lower(), 'sample')])
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   535
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   536
    def sample_filename(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   537
        return os.path.join(self.sample_dir(), '%s %s.jpg' % (self.name.lower(), 'sample'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   538
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   539
    def create_sample(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   540
        if not os.path.isdir(self.sample_dir()):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   541
            os.makedirs(self.sample_dir())
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   542
        try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   543
            im = Image.open(SAMPLE_IMAGE_PATH)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   544
        except IOError:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   545
            raise IOError('Photologue was unable to open the sample image: %s.' % SAMPLE_IMAGE_PATH)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   546
        im = self.process(im)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   547
        im.save(self.sample_filename(), 'JPEG', quality=90, optimize=True)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   548
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   549
    def admin_sample(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   550
        return u'<img src="%s">' % self.sample_url()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   551
    admin_sample.short_description = 'Sample'
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   552
    admin_sample.allow_tags = True
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   553
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   554
    def pre_process(self, im):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   555
        return im
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   556
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   557
    def post_process(self, im):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   558
        return im
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   559
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   560
    def process(self, im):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   561
        im = self.pre_process(im)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   562
        im = self.post_process(im)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   563
        return im
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   564
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   565
    def __unicode__(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   566
        return self.name
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   567
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   568
    def __str__(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   569
        return self.__unicode__()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   570
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   571
    def save(self, *args, **kwargs):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   572
        try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   573
            os.remove(self.sample_filename())
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   574
        except:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   575
            pass
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   576
        models.Model.save(self, *args, **kwargs)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   577
        self.create_sample()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   578
        for size in self.photo_sizes.all():
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   579
            size.clear_cache()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   580
        # try to clear all related subclasses of ImageModel
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   581
        for prop in [prop for prop in dir(self) if prop[-8:] == '_related']:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   582
            for obj in getattr(self, prop).all():
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   583
                obj.clear_cache()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   584
                obj.pre_cache()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   585
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   586
    def delete(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   587
        try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   588
            os.remove(self.sample_filename())
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   589
        except:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   590
            pass
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   591
        models.Model.delete(self)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   592
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   593
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   594
class PhotoEffect(BaseEffect):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   595
    """ A pre-defined effect to apply to photos """
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   596
    transpose_method = models.CharField(_('rotate or flip'), max_length=15, blank=True, choices=IMAGE_TRANSPOSE_CHOICES)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   597
    color = models.FloatField(_('color'), default=1.0, help_text=_("A factor of 0.0 gives a black and white image, a factor of 1.0 gives the original image."))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   598
    brightness = models.FloatField(_('brightness'), default=1.0, help_text=_("A factor of 0.0 gives a black image, a factor of 1.0 gives the original image."))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   599
    contrast = models.FloatField(_('contrast'), default=1.0, help_text=_("A factor of 0.0 gives a solid grey image, a factor of 1.0 gives the original image."))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   600
    sharpness = models.FloatField(_('sharpness'), default=1.0, help_text=_("A factor of 0.0 gives a blurred image, a factor of 1.0 gives the original image."))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   601
    filters = models.CharField(_('filters'), max_length=200, blank=True, help_text=_(IMAGE_FILTERS_HELP_TEXT))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   602
    reflection_size = models.FloatField(_('size'), default=0, help_text=_("The height of the reflection as a percentage of the orignal image. A factor of 0.0 adds no reflection, a factor of 1.0 adds a reflection equal to the height of the orignal image."))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   603
    reflection_strength = models.FloatField(_('strength'), default=0.6, help_text=_("The initial opacity of the reflection gradient."))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   604
    background_color = models.CharField(_('color'), max_length=7, default="#FFFFFF", help_text=_("The background color of the reflection gradient. Set this to match the background color of your page."))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   605
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   606
    class Meta:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   607
        verbose_name = _("photo effect")
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   608
        verbose_name_plural = _("photo effects")
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   609
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   610
    def pre_process(self, im):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   611
        if self.transpose_method != '':
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   612
            method = getattr(Image, self.transpose_method)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   613
            im = im.transpose(method)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   614
        if im.mode != 'RGB' and im.mode != 'RGBA':
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   615
            return im
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   616
        for name in ['Color', 'Brightness', 'Contrast', 'Sharpness']:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   617
            factor = getattr(self, name.lower())
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   618
            if factor != 1.0:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   619
                im = getattr(ImageEnhance, name)(im).enhance(factor)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   620
        for name in self.filters.split('->'):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   621
            image_filter = getattr(ImageFilter, name.upper(), None)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   622
            if image_filter is not None:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   623
                try:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   624
                    im = im.filter(image_filter)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   625
                except ValueError:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   626
                    pass
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   627
        return im
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   628
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   629
    def post_process(self, im):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   630
        if self.reflection_size != 0.0:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   631
            im = add_reflection(im, bgcolor=self.background_color, amount=self.reflection_size, opacity=self.reflection_strength)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   632
        return im
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   633
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   634
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   635
class Watermark(BaseEffect):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   636
    image = models.ImageField(_('image'), upload_to=PHOTOLOGUE_DIR+"/watermarks")
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   637
    style = models.CharField(_('style'), max_length=5, choices=WATERMARK_STYLE_CHOICES, default='scale')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   638
    opacity = models.FloatField(_('opacity'), default=1, help_text=_("The opacity of the overlay."))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   639
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   640
    class Meta:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   641
        verbose_name = _('watermark')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   642
        verbose_name_plural = _('watermarks')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   643
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   644
    def post_process(self, im):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   645
        mark = Image.open(self.image.path)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   646
        return apply_watermark(im, mark, self.style, self.opacity)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   647
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   648
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   649
class PhotoSize(models.Model):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   650
    name = models.CharField(_('name'), max_length=20, unique=True, help_text=_('Photo size name should contain only letters, numbers and underscores. Examples: "thumbnail", "display", "small", "main_page_widget".'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   651
    width = models.PositiveIntegerField(_('width'), default=0, help_text=_('If width is set to "0" the image will be scaled to the supplied height.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   652
    height = models.PositiveIntegerField(_('height'), default=0, help_text=_('If height is set to "0" the image will be scaled to the supplied width'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   653
    quality = models.PositiveIntegerField(_('quality'), choices=JPEG_QUALITY_CHOICES, default=70, help_text=_('JPEG image quality.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   654
    upscale = models.BooleanField(_('upscale images?'), default=False, help_text=_('If selected the image will be scaled up if necessary to fit the supplied dimensions. Cropped sizes will be upscaled regardless of this setting.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   655
    crop = models.BooleanField(_('crop to fit?'), default=False, help_text=_('If selected the image will be scaled and cropped to fit the supplied dimensions.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   656
    pre_cache = models.BooleanField(_('pre-cache?'), default=False, help_text=_('If selected this photo size will be pre-cached as photos are added.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   657
    increment_count = models.BooleanField(_('increment view count?'), default=False, help_text=_('If selected the image\'s "view_count" will be incremented when this photo size is displayed.'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   658
    effect = models.ForeignKey('PhotoEffect', null=True, blank=True, related_name='photo_sizes', verbose_name=_('photo effect'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   659
    watermark = models.ForeignKey('Watermark', null=True, blank=True, related_name='photo_sizes', verbose_name=_('watermark image'))
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   660
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   661
    class Meta:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   662
        ordering = ['width', 'height']
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   663
        verbose_name = _('photo size')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   664
        verbose_name_plural = _('photo sizes')
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   665
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   666
    def __unicode__(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   667
        return self.name
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   668
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   669
    def __str__(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   670
        return self.__unicode__()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   671
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   672
    def clear_cache(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   673
        for cls in ImageModel.__subclasses__():
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   674
            for obj in cls.objects.all():
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   675
                obj.remove_size(self)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   676
                if self.pre_cache:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   677
                    obj.create_size(self)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   678
        PhotoSizeCache().reset()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   679
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   680
    def save(self, *args, **kwargs):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   681
        if self.crop is True:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   682
            if self.width == 0 or self.height == 0:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   683
                raise ValueError("PhotoSize width and/or height can not be zero if crop=True.")
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   684
        super(PhotoSize, self).save(*args, **kwargs)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   685
        PhotoSizeCache().reset()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   686
        self.clear_cache()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   687
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   688
    def delete(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   689
        assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   690
        self.clear_cache()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   691
        super(PhotoSize, self).delete()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   692
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   693
    def _get_size(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   694
        return (self.width, self.height)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   695
    def _set_size(self, value):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   696
        self.width, self.height = value
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   697
    size = property(_get_size, _set_size)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   698
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   699
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   700
class PhotoSizeCache(object):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   701
    __state = {"sizes": {}}
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   702
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   703
    def __init__(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   704
        self.__dict__ = self.__state
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   705
        if not len(self.sizes):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   706
            sizes = PhotoSize.objects.all()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   707
            for size in sizes:
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   708
                self.sizes[size.name] = size
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   709
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   710
    def reset(self):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   711
        self.sizes = {}
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   712
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   713
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   714
# Set up the accessor methods
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   715
def add_methods(sender, instance, signal, *args, **kwargs):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   716
    """ Adds methods to access sized images (urls, paths)
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   717
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   718
    after the Photo model's __init__ function completes,
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   719
    this method calls "add_accessor_methods" on each instance.
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   720
    """
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   721
    if hasattr(instance, 'add_accessor_methods'):
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   722
        instance.add_accessor_methods()
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   723
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   724
# connect the add_accessor_methods function to the post_init signal
10b1f6d8a5d2 first debug version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   725
post_init.connect(add_methods)