from django.conf import settings from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.db import models from django.db.models import Avg class Rating(models.Model): score = models.PositiveSmallIntegerField(choices=[(i, str(i)) for i in range(1, 6)], verbose_name="Puan") comment = models.TextField(blank=True, null=True, verbose_name="Yorum") # Generic Relation Fields content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='ratings') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: unique_together = ('content_type', 'object_id', 'user') # Bir kullanıcı bir şeye sadece bir kez oy verebilir ordering = ['-created_at'] verbose_name = "Değerlendirme" verbose_name_plural = "Değerlendirmeler" def __str__(self): return f"{self.score} - {self.content_object}" # Bu Mixin'i oylanabilir olmasını istediğiniz modellere miras (inherit) verebilirsiniz. class RateableMixin: @property def average_rating(self): # İlgili nesneye ait tüm oyların ortalamasını alır ratings = Rating.objects.filter( content_type=ContentType.objects.get_for_model(self), object_id=self.id ) return ratings.aggregate(Avg('score'))['score__avg'] or 0.0 @property def rating_count(self): # Toplam oy sayısını döndürür return Rating.objects.filter( content_type=ContentType.objects.get_for_model(self), object_id=self.id ).count()