muistox/gallery/models/photo.py

87 lines
No EOL
3.3 KiB
Python

import os
from datetime import datetime
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.urls import reverse
from django.utils.text import slugify
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFit
from gallery.exif import Exif
from gallery.models import Album
def get_upload_path(instance, filename):
return os.path.join('albums', str(instance.album.slug), filename)
class Photo(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE, related_name='photos', verbose_name="Album")
slug = models.CharField(max_length=50, 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"
@property
def aspect_ratio(self):
return self.width / self.height
def save(self, *args, **kwargs):
if not self.slug:
self.slug = os.path.basename(self.photo.name)
super().save(*args, **kwargs)
def add_like(self):
self.likes += 1
self.save(update_fields=['likes'])
def add_view(self):
self.views += 1
self.save(update_fields=['views'])
def get_next(self):
return self.__class__.objects.filter(taken_at__gt=self.taken_at, album=self.album).order_by('taken_at').first()
def get_prev(self):
return self.__class__.objects.filter(taken_at__lt=self.taken_at, album=self.album).order_by('-taken_at').first()
def get_absolute_url(self):
return reverse('gallery:photo_url', kwargs={'album_slug': self.album.slug, 'photo_slug': self.slug})
class Meta:
unique_together = ('album', "slug")
verbose_name_plural = "Photos"
ordering = ('-taken_at',)
def __str__(self):
return f'{self.slug} ({self.orientation}) {self.is_favorite}'
def create_photo(sender, instance, created, **kwargs):
if created:
""" Add exif metadata """
exif = Exif(instance.photo.path)
instance.exif = exif.data
""" Update taken datetime """
instance.taken_at = exif.datetimeoriginal('Europe/Helsinki')
instance.save()
post_save.connect(create_photo, sender=Photo)