from django.db import models from django.contrib.auth import get_user_model from django.core.validators import MinValueValidator, MaxValueValidator from django.db.models import Avg User = get_user_model() class Rate(models.Model): """ Rate model for different services like library, podcast, hadith, and video. Users can rate content from 1 to 5. """ class ServiceChoices(models.TextChoices): LIBRARY = 'library', 'Library' PODCAST = 'podcast', 'Podcast' HADITH = 'hadith', 'Hadith' VIDEO = 'video', 'Video' VIDEO_PLAYLIST = 'video_playlist', 'Video Playlist' user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='rates', verbose_name='User') service = models.CharField(max_length=20, choices=ServiceChoices.choices, verbose_name='Service') content_id = models.PositiveIntegerField(verbose_name='Content ID') rate = models.PositiveSmallIntegerField( validators=[MinValueValidator(1), MaxValueValidator(5)], verbose_name='Rate' ) status = models.BooleanField(default=True, verbose_name='Status') created_at = models.DateTimeField(auto_now_add=True, verbose_name='Created At') updated_at = models.DateTimeField(auto_now=True, verbose_name='Updated At') class Meta: verbose_name = 'Rate' verbose_name_plural = 'Rates' unique_together = ('user', 'service', 'content_id') def __str__(self): return f"{self.user.username} - {self.get_service_display()} - {self.content_id} - {self.rate}" @classmethod def get_user_rate(cls, user, service, content_id): """ Get the rate information for a specific content by the user. Args: user: User instance service: Service name (library, podcast, hadith, video) content_id: ID of the content Returns: Dictionary containing: - is_rated: Boolean indicating if the content is rated by the user - rate: The rate value given by the user (1-5) or None if not rated """ try: rate_obj = cls.objects.get( user=user, service=service, content_id=content_id, status=True ) return { 'is_rated': True, 'rate': rate_obj.rate } except cls.DoesNotExist: return { 'is_rated': False, 'rate': None } @classmethod def validate_content_exists(cls, service, content_id): """ Validate if content with the given ID exists in the specified service. Args: service: Service name (library, podcast, hadith, video) content_id: ID of the content to validate Returns: Boolean indicating if the content exists """ if service == cls.ServiceChoices.LIBRARY: from apps.library.models import Book return Book.objects.filter(id=content_id).exists() elif service == cls.ServiceChoices.PODCAST: from apps.podcast.models import Podcast return Podcast.objects.filter(id=content_id).exists() elif service == cls.ServiceChoices.HADITH: from apps.hadith.models import Hadith return Hadith.objects.filter(id=content_id).exists() elif service == cls.ServiceChoices.VIDEO: from apps.video.models import Video return Video.objects.filter(id=content_id).exists() elif service == cls.ServiceChoices.VIDEO_PLAYLIST: from apps.video.models import VideoPlaylist return VideoPlaylist.objects.filter(id=content_id).exists() return False @classmethod def get_average_rate(cls, service, content_id): """ Get the average rate for a specific content. Args: service: Service name (library, podcast, hadith, video) content_id: ID of the content Returns: Float representing the average rate (1-5) or None if no rates """ result = cls.objects.filter( service=service, content_id=content_id, status=True ).aggregate(avg_rate=Avg('rate')) return result['avg_rate']