from django.db import models from django.utils import timezone from django.utils.text import slugify class CaseStudyCategory(models.Model): """Model for case study categories""" name = models.CharField(max_length=100) slug = models.SlugField(max_length=100, unique=True) description = models.TextField(blank=True) display_order = models.PositiveIntegerField(default=0) is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: verbose_name = "Case Study Category" verbose_name_plural = "Case Study Categories" ordering = ['display_order', 'name'] def __str__(self): return self.name def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name) super().save(*args, **kwargs) class Client(models.Model): """Model for clients""" name = models.CharField(max_length=200) slug = models.SlugField(max_length=200, unique=True) logo = models.ImageField(upload_to='case_studies/clients/', blank=True, null=True) logo_url = models.CharField(max_length=500, blank=True, help_text="External logo URL") description = models.TextField(blank=True) website = models.URLField(blank=True) is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: verbose_name = "Client" verbose_name_plural = "Clients" ordering = ['name'] def __str__(self): return self.name def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name) super().save(*args, **kwargs) @property def get_logo_url(self): """Return the logo URL (uploaded image or external URL)""" if self.logo and hasattr(self.logo, 'url'): return self.logo.url elif self.logo_url: return self.logo_url return None class CaseStudy(models.Model): """Model for case studies""" title = models.CharField(max_length=300) slug = models.SlugField(max_length=300, unique=True) subtitle = models.CharField(max_length=300, blank=True) description = models.TextField() excerpt = models.TextField(blank=True, help_text="Short excerpt for preview") # Images thumbnail = models.ImageField(upload_to='case_studies/thumbnails/', blank=True, null=True) thumbnail_url = models.CharField(max_length=500, blank=True, help_text="External thumbnail URL") featured_image = models.ImageField(upload_to='case_studies/featured/', blank=True, null=True) featured_image_url = models.CharField(max_length=500, blank=True, help_text="External featured image URL") poster_image = models.ImageField(upload_to='case_studies/posters/', blank=True, null=True) poster_image_url = models.CharField(max_length=500, blank=True, help_text="External poster image URL") project_image = models.ImageField(upload_to='case_studies/projects/', blank=True, null=True) project_image_url = models.CharField(max_length=500, blank=True, help_text="External project image URL") # Content sections project_overview = models.TextField(blank=True, help_text="Project overview content") site_map_content = models.TextField(blank=True, help_text="Site map / process content") # Relations category = models.ForeignKey( CaseStudyCategory, on_delete=models.SET_NULL, null=True, related_name='case_studies' ) client = models.ForeignKey( Client, on_delete=models.SET_NULL, null=True, blank=True, related_name='case_studies' ) # SEO and metadata meta_description = models.CharField(max_length=160, blank=True) meta_keywords = models.CharField(max_length=255, blank=True) # Status and visibility published = models.BooleanField(default=True) featured = models.BooleanField(default=False, help_text="Featured case study") views_count = models.PositiveIntegerField(default=0) display_order = models.PositiveIntegerField(default=0) # Timestamps published_at = models.DateTimeField(default=timezone.now) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: verbose_name = "Case Study" verbose_name_plural = "Case Studies" ordering = ['display_order', '-published_at', '-created_at'] indexes = [ models.Index(fields=['-published_at']), models.Index(fields=['slug']), models.Index(fields=['published']), ] def __str__(self): return self.title def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.title) if not self.excerpt and self.description: # Generate excerpt from description (first 200 characters) self.excerpt = self.description[:200] + '...' if len(self.description) > 200 else self.description super().save(*args, **kwargs) @property def get_thumbnail_url(self): """Return the thumbnail URL (uploaded image or external URL)""" if self.thumbnail and hasattr(self.thumbnail, 'url'): return self.thumbnail.url elif self.thumbnail_url: return self.thumbnail_url return None @property def get_featured_image_url(self): """Return the featured image URL (uploaded image or external URL)""" if self.featured_image and hasattr(self.featured_image, 'url'): return self.featured_image.url elif self.featured_image_url: return self.featured_image_url return None @property def get_poster_image_url(self): """Return the poster image URL (uploaded image or external URL)""" if self.poster_image and hasattr(self.poster_image, 'url'): return self.poster_image.url elif self.poster_image_url: return self.poster_image_url return None @property def get_project_image_url(self): """Return the project image URL (uploaded image or external URL)""" if self.project_image and hasattr(self.project_image, 'url'): return self.project_image.url elif self.project_image_url: return self.project_image_url return None def increment_views(self): """Increment the view count""" self.views_count += 1 self.save(update_fields=['views_count']) class CaseStudyImage(models.Model): """Model for additional case study images (gallery)""" case_study = models.ForeignKey(CaseStudy, on_delete=models.CASCADE, related_name='gallery_images') image = models.ImageField(upload_to='case_studies/gallery/') image_url = models.CharField(max_length=500, blank=True, help_text="External image URL") caption = models.CharField(max_length=200, blank=True) display_order = models.PositiveIntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) class Meta: verbose_name = "Case Study Image" verbose_name_plural = "Case Study Images" ordering = ['display_order', 'created_at'] def __str__(self): return f"{self.case_study.title} - Image {self.display_order}" @property def get_image_url(self): """Return the image URL (uploaded image or external URL)""" if self.image and hasattr(self.image, 'url'): return self.image.url elif self.image_url: return self.image_url return None class CaseStudyProcess(models.Model): """Model for case study process steps""" case_study = models.ForeignKey(CaseStudy, on_delete=models.CASCADE, related_name='process_steps') title = models.CharField(max_length=200) description = models.TextField() step_number = models.PositiveIntegerField() created_at = models.DateTimeField(auto_now_add=True) class Meta: verbose_name = "Case Study Process" verbose_name_plural = "Case Study Processes" ordering = ['step_number'] def __str__(self): return f"{self.case_study.title} - Step {self.step_number}: {self.title}"