import uuid from django.conf import settings from django.db import models from django.utils import timezone class ImageSession(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) original_image = models.CharField(max_length=255) processed_image = models.CharField(max_length=255, blank=True) width = models.PositiveIntegerField() height = models.PositiveIntegerField() channels = models.PositiveSmallIntegerField() color_mode = models.CharField(max_length=16) original_histogram = models.JSONField(default=list) processed_histogram = models.JSONField(default=list, blank=True) created_at = models.DateTimeField(auto_now_add=True) expires_at = models.DateTimeField() def save(self, *args, **kwargs): if not self.expires_at: self.expires_at = timezone.now() + timezone.timedelta(hours=settings.IMAGE_SESSION_TTL_HOURS) super().save(*args, **kwargs) @property def expired(self): return timezone.now() >= self.expires_at class ImageState(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) session = models.ForeignKey(ImageSession, related_name="states", on_delete=models.CASCADE) parent = models.ForeignKey("self", related_name="children", on_delete=models.SET_NULL, null=True, blank=True) sequence = models.PositiveIntegerField(default=0) label = models.CharField(max_length=120) operation = models.CharField(max_length=96) params = models.JSONField(default=dict, blank=True) image = models.CharField(max_length=255) width = models.PositiveIntegerField() height = models.PositiveIntegerField() channels = models.PositiveSmallIntegerField() color_mode = models.CharField(max_length=16) histogram = models.JSONField(default=dict) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ["sequence", "created_at"] class ProcessingJob(models.Model): STATUS_PENDING = "pending" STATUS_RUNNING = "running" STATUS_COMPLETE = "complete" STATUS_FAILED = "failed" STATUS_CHOICES = [ (STATUS_PENDING, "Pending"), (STATUS_RUNNING, "Running"), (STATUS_COMPLETE, "Complete"), (STATUS_FAILED, "Failed"), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) operation = models.CharField(max_length=64) params = models.JSONField(default=dict, blank=True) status = models.CharField(max_length=16, choices=STATUS_CHOICES, default=STATUS_PENDING) progress = models.PositiveSmallIntegerField(default=0) result_image = models.CharField(max_length=255, blank=True) result_histogram = models.JSONField(default=list, blank=True) error = models.TextField(blank=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True)