from django.db import models from django.core.validators import MinValueValidator, MaxValueValidator from django.urls import reverse from datetime import date class Platform(models.Model): """Model representing different social media/content platforms""" PLATFORM_TYPES = [ ('linkedin', 'LinkedIn'), ('youtube', 'YouTube'), ('blog', 'Blog'), ('instagram', 'Instagram'), ('twitter', 'Twitter'), ('facebook', 'Facebook'), ('tiktok', 'TikTok'), ('podcast', 'Podcast'), ('newsletter', 'Newsletter'), ('other', 'Other'), ] STATUS_CHOICES = [ ('active', 'Active'), ('inactive', 'Inactive'), ('planning', 'Planning'), ('paused', 'Paused'), ] name = models.CharField(max_length=100, help_text="Platform name (e.g., 'LinkedIn Business')") platform_type = models.CharField(max_length=20, choices=PLATFORM_TYPES) description = models.TextField(blank=True, help_text="Brief description of this platform's purpose") status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active') primary_content_type = models.CharField( max_length=100, help_text="Main type of content for this platform (e.g., 'Articles', 'Videos', 'Posts')" ) target_audience = models.CharField( max_length=200, blank=True, help_text="Target audience for this platform" ) posting_frequency = models.CharField( max_length=100, blank=True, help_text="How often content is posted (e.g., 'Daily', '3x per week')" ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['name'] def __str__(self): return f"{self.name} ({self.get_platform_type_display()})" def get_absolute_url(self): return reverse('platform-detail', args=[str(self.id)]) @property def total_deliverables(self): return self.contentdeliverable_set.count() @property def committed_count(self): return self.contentdeliverable_set.filter(status='committed').count() @property def drafted_count(self): return self.contentdeliverable_set.filter(status='drafted').count() @property def published_count(self): return self.contentdeliverable_set.filter(status='published').count() @property def completion_rate(self): total = self.total_deliverables if total == 0: return 0 published = self.published_count return round((published / total) * 100, 1) class Strategy(models.Model): """Model for platform strategies containing objectives, tactics, and actions""" platform = models.ForeignKey(Platform, on_delete=models.CASCADE, related_name='strategies') title = models.CharField(max_length=200, help_text="Strategy title") objective = models.TextField(help_text="What you want to achieve") tactics = models.TextField(help_text="How you plan to achieve the objective") actions = models.TextField(help_text="Specific actions to implement the tactics") control = models.TextField( blank=True, help_text="How you'll measure success and control/adjust the strategy" ) priority = models.IntegerField( default=1, validators=[MinValueValidator(1), MaxValueValidator(5)], help_text="Priority level (1 = highest, 5 = lowest)" ) start_date = models.DateField(default=date.today) end_date = models.DateField(blank=True, null=True) is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['priority', '-created_at'] verbose_name_plural = 'strategies' def __str__(self): return f"{self.platform.name} - {self.title}" class ContentDeliverable(models.Model): """Model for tracking content deliverables and their progress""" STATUS_CHOICES = [ ('committed', 'Committed'), ('drafted', 'Drafted'), ('published', 'Published'), ('cancelled', 'Cancelled'), ] CONTENT_TYPES = [ ('article', 'Article'), ('video', 'Video'), ('post', 'Social Media Post'), ('story', 'Story'), ('reel', 'Reel/Short Video'), ('carousel', 'Carousel'), ('infographic', 'Infographic'), ('podcast', 'Podcast Episode'), ('newsletter', 'Newsletter'), ('other', 'Other'), ] platform = models.ForeignKey(Platform, on_delete=models.CASCADE) title = models.CharField(max_length=200, help_text="Content title or brief description") content_type = models.CharField(max_length=20, choices=CONTENT_TYPES) status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='committed') description = models.TextField(blank=True, help_text="Detailed description of the content") completion_percentage = models.IntegerField( default=0, validators=[MinValueValidator(0), MaxValueValidator(100)], help_text="Completion progress (0-100%)" ) target_date = models.DateField(blank=True, null=True, help_text="Target publication date") actual_date = models.DateField(blank=True, null=True, help_text="Actual publication date") url = models.URLField(blank=True, help_text="URL of published content") notes = models.TextField(blank=True, help_text="Additional notes or comments") tags = models.CharField( max_length=200, blank=True, help_text="Comma-separated tags (e.g., 'marketing, tutorial, beginner')" ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['-created_at'] def __str__(self): return f"{self.platform.name} - {self.title} ({self.get_status_display()})" def get_absolute_url(self): return reverse('deliverable-detail', args=[str(self.id)]) @property def is_overdue(self): if self.target_date and self.status not in ['published', 'cancelled']: return date.today() > self.target_date return False @property def days_until_due(self): if self.target_date: delta = self.target_date - date.today() return delta.days return None