from django.contrib.postgres.fields import ArrayField from django.db import models from django.dispatch import receiver from django.contrib.auth import get_user_model from model_utils import FieldTracker from . import tasks from colorfield.fields import ColorField from datetime import date import os import uuid UserModel = get_user_model() class PhotoTag(models.Model): name = models.CharField(unique=True, null=False, blank=False, max_length=100) color = ColorField(default='#FFE5B4') def __str__(self): return self.name class Meta: ordering = ('name',) class PhotoGroup(models.Model): name = models.CharField(unique=False, null=False, max_length=200) date = models.DateField(null=True) parent = models.ForeignKey('self', blank=True, null=True, on_delete=models.SET_NULL) owner = models.ForeignKey( UserModel, on_delete=models.CASCADE, related_name='photogroups', ) def __str__(self): return self.name def get_default_photogroup(): return PhotoGroup.objects.get_or_create( name="Unsortiert", date=None, ) def get_original_photo_path(instance, filename): _, ext = os.path.splitext(filename) return 'original_images/%s%s' % (str(uuid.uuid4()), ext) def get_cropped_photo_path(instance, filename): _, ext = os.path.splitext(filename) return 'cropped_images/%s%s' % (str(uuid.uuid4()), ext) class Photo(models.Model): legacy_id = models.IntegerField(unique=True, blank=True, null=True) original_image = models.ImageField(upload_to=get_original_photo_path, null=False, blank=False) cropped_image = models.ImageField(upload_to=get_cropped_photo_path, null=True, blank=True) bbox_coords = ArrayField( ArrayField( models.IntegerField(unique=False, blank=False, null=True, default=None), size=2 ), blank=True, null=True, default=None, size=4, ) rotate = models.FloatField(blank=True, null=True) intersections = ArrayField( ArrayField( models.IntegerField(unique=False, blank=False, null=True, default=None), size=2 ), blank=True, null=True, default=None ) group = models.ForeignKey( PhotoGroup, null=False, blank=True, on_delete=models.SET_DEFAULT, default=get_default_photogroup ) ocr_text = models.CharField(max_length=200, null=True, blank=True) tag = models.ForeignKey( PhotoTag, null=True, blank=False, on_delete=models.SET_NULL, default=None, ) owner = models.ForeignKey( UserModel, on_delete=models.CASCADE, related_name='photos', ) tracker = FieldTracker() def __str__(self): return "Photo #" + str(self.id) @receiver(models.signals.post_delete, sender=Photo) def auto_delete_file_on_delete(sender, instance, **kwargs): if instance.original_image: instance.original_image.delete(save=False) if instance.cropped_image: instance.cropped_image.delete(save=False) @receiver(models.signals.pre_save, sender=Photo) def auto_delete_file_on_change(sender, instance, **kwargs): if not instance.pk: return False try: photo = Photo.objects.get(pk=instance.pk) except Photo.DoesNotExist: return False # check original image for change new_file = instance.original_image old_file = photo.original_image if not old_file == new_file: photo.original_image.delete(save=False) # check cropped image for change new_file = instance.cropped_image old_file = photo.cropped_image if not old_file == new_file: photo.cropped_image.delete(save=False) @receiver(models.signals.post_save, sender=Photo) def max_resize_images(sender, instance, **kwargs): MAX_IMAGE_WIDTH = 800 tracker = instance.tracker original_image_s3_path = instance.original_image.name if original_image_s3_path and tracker.has_changed('original_image'): tasks.max_resize_image_chain(original_image_s3_path, MAX_IMAGE_WIDTH) cropped_image_s3_path = instance.cropped_image.name if cropped_image_s3_path and tracker.has_changed('cropped_image'): tasks.max_resize_image_chain(cropped_image_s3_path, MAX_IMAGE_WIDTH) def get_empty_photolog_default(): return [] def get_photolog_pdf_path(instance, filename): return "photolog_pdf/%s.pdf" % str(uuid.uuid4()) class PhotoLog(models.Model): title = models.CharField(null=False, blank=False, max_length=5000) date = models.DateField(auto_now=False, default=date.today) render_date = models.BooleanField(null=False, blank=True, default=True) start_slide_image = models.IntegerField(null=True, blank=True, default=3) slides = ArrayField( ArrayField( models.IntegerField(blank=False, null=True), null=True, blank=True, size=3 ), null=False, blank=True, default=get_empty_photolog_default ) pdf = models.FileField(upload_to=get_photolog_pdf_path, null=True, blank=True) def __str__(self): return self.title class PhotoLogTemplate(models.Model): title = models.CharField(null=False, blank=False, max_length=5000) date = models.DateField(auto_now=False, default=date.today) render_date = models.BooleanField(null=False, blank=True, default=True) start_slide_image = models.IntegerField(null=True, blank=True, default=3) slides = models.JSONField( null=False, blank=False, default=list, ) def __str__(self): return self.title @receiver(models.signals.post_delete, sender=PhotoLog) def auto_delete_file_on_delete(sender, instance, **kwargs): if instance.pdf: instance.pdf.delete(save=False)