models.py 3.78 KB
Newer Older
1
import hashlib
2
3
4
import os
import random

5
6
7
8
from django.conf import settings
from django.db import models
from django.urls import reverse
from django.utils.functional import cached_property
9
from django.utils.translation import ugettext_lazy as _
10
11
from PIL import Image

12
13
14
COVER_FILENAME = 'cover.jpg'


15
def photo_uploadto(instance, filename):
16
17
18
19
    num = instance.album.photo_set.count()
    _, extension = os.path.splitext(filename)
    new_filename = str(num).zfill(4) + extension
    return os.path.join(Album.photosdir, instance.album.dirname, new_filename)
20
21
22


class Photo(models.Model):
23
24
25
26
27
28
29
30
31
32
33
    album = models.ForeignKey(
        'Album',
        on_delete=models.CASCADE,
        verbose_name=_("album")
    )

    file = models.ImageField(
        _('file'),
        upload_to=photo_uploadto
    )

Joost Rijneveld's avatar
Joost Rijneveld committed
34
    rotation = models.IntegerField(
35
        verbose_name=_('rotation'),
Joost Rijneveld's avatar
Joost Rijneveld committed
36
37
        default=0,
        choices=((x, x) for x in (0, 90, 180, 270)),
38
39
40
41
42
43
        help_text=_('This does not modify the original image file.'),
    )

    hidden = models.BooleanField(
        _('hidden'),
        default=False
Joost Rijneveld's avatar
Joost Rijneveld committed
44
    )
45

46
47
48
49
50
    _digest = models.CharField(
        'digest',
        max_length=40,
    )

51
52
53
54
55
56
57
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.file:
            self._orig_file = self.file.path
        else:
            self._orig_file = ""

58
59
60
    def __str__(self):
        return self.file.name

61
62
63
    def save(self, *args, **kwargs):
        super(Photo, self).save(*args, **kwargs)

64
        if self._orig_file != self.file.path:
65
            image_path = self.file.path
66
            image = Image.open(image_path)
67
            # Image.thumbnail does not upscale an image that is smaller
68
69
            image.thumbnail(settings.PHOTO_UPLOAD_SIZE, Image.ANTIALIAS)
            image.save(image_path, "JPEG")
70
            self._orig_file = self.file.path
71

72
73
74
75
76
            hash_sha1 = hashlib.sha1()
            for chunk in iter(lambda: self.file.read(4096), b""):
                hash_sha1.update(chunk)
            self._digest = hash_sha1.hexdigest()

77
78
79
    class Meta:
        ordering = ('file', )

80

81
class Album(models.Model):
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
    title = models.CharField(
        verbose_name=_('title'),
        max_length=200,
    )

    dirname = models.CharField(
        verbose_name=_('directory name'),
        max_length=200,
    )

    date = models.DateField(
        verbose_name=_('date'),
    )

    slug = models.SlugField(
        verbose_name=_('slug'),
    )

    hidden = models.BooleanField(
        verbose_name=_('hidden'),
        default=False
    )

    _cover = models.OneToOneField(
        Photo,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
        related_name='covered_album',
        verbose_name=_('cover image'),
    )

    shareable = models.BooleanField(
        verbose_name=_('shareable'),
        default=False
    )
118
119
120
121
122
123

    photosdir = 'photos'
    photospath = os.path.join(settings.MEDIA_ROOT, photosdir)

    @cached_property
    def cover(self):
124
125
        if self._cover is not None:
            return self._cover
126
127
        else:
            random.seed(self.dirname)
128
129
            cover = random.choice(self.photo_set.all())
        return cover
130

131
132
133
134
    def __str__(self):
        return '{} {}'.format(self.date.strftime('%Y-%m-%d'), self.title)

    def get_absolute_url(self):
135
        return reverse('photos:album', args=[str(self.slug)])
136
137

    def save(self, *args, **kwargs):
138
139
140
141
        # dirname is only set for new objects, to avoid ever changing it
        if self.pk is None:
            self.dirname = self.slug
        super(Album, self).save(*args, **kwargs)
142
143
144
145
146

    @property
    def access_token(self):
        return hashlib.sha256('{}album{}'.format(settings.SECRET_KEY, self.pk)
                              .encode('utf-8')).hexdigest()
147
148
149

    class Meta:
        ordering = ('-date', 'title')