import os from datetime import datetime from django.db import models from django.urls import reverse from imagekit.models import ImageSpecField from imagekit.processors import ResizeToFit from gallery.exif import Exif from gallery.models import Album class Photo(models.Model): def _get_upload_path(instance, filename): return os.path.join('albums', str(instance.album.slug), filename) def _generate_unique_slug(self, datetime_taken=datetime.now()): slug = int(datetime_taken.strftime('%y%m%d%H%M%S')) while Photo.objects.filter(album=self.album, slug=slug).exists(): slug += 1 return str(slug) album = models.ForeignKey(Album, on_delete=models.CASCADE, related_name='photos', verbose_name="Album") slug = models.CharField(max_length=15, editable=False, verbose_name="Photo Slug") photo = models.ImageField(upload_to=_get_upload_path, height_field='height', width_field='width', verbose_name="Photo") photo_sm = ImageSpecField(source='photo', processors=[ResizeToFit(320, 320)], format='JPEG', options={'quality': 70}) photo_md = ImageSpecField(source='photo', processors=[ResizeToFit(720, 720)], format='JPEG', options={'quality': 80}) photo_bg = ImageSpecField(source='photo', processors=[ResizeToFit(1920, 1920)], format='JPEG', options={'quality': 90}) width = models.PositiveIntegerField(default=0, editable=False, verbose_name="Photo Width") height = models.PositiveIntegerField(default=0, editable=False, verbose_name="Photo Height") taken_at = models.DateTimeField(blank=True, null=True, editable=False, verbose_name="Taken at") exif = models.JSONField(blank=True, null=True, editable=False, verbose_name="Exif Metadata") is_favorite = models.BooleanField(default=False, verbose_name="Is Favorite") views = models.PositiveIntegerField(default=0, verbose_name="Views") likes = models.PositiveIntegerField(default=0, verbose_name="Likes") @property def orientation(self): return "Portrait" if self.height > self.width else "Landscape" def add_like(self): self.likes += 1 self.save() def add_view(self): self.views += 1 self.save() def get_next(self): return self.__class__.objects.filter(taken_at__gt=self.taken_at, album=self.album.id).order_by('taken_at').first() def get_prev(self): return self.__class__.objects.filter(taken_at__lt=self.taken_at, album=self.album.id).order_by('-taken_at').first() def save(self, *args, **kwargs): self.exif_data = Exif(self.photo.path) datetime_taken = getattr(self.exif_data, 'datetimeoriginal', datetime.now)() self.slug = self.slug or self._generate_unique_slug(datetime_taken) self.taken_at = self.taken_at or datetime_taken self.exif = getattr(self.exif_data, 'data', None) super().save(*args, **kwargs) def get_absolute_url(self): return reverse('gallery:photo_url', kwargs={'album_slug': self.album.slug, 'photo_slug': self.slug}) class Meta: verbose_name_plural = "Photos" ordering = ('-taken_at',) def __str__(self): return f'{self.slug} ({self.orientation}) {self.is_favorite}'