Генерировать среднее значение для оценок в моделях Django и возвращать с другой моделью

#python #django #python-3.x #django-models #django-2.0

#python #django #python-3.x #django-модели #django-2.0

Вопрос:

Я работаю над проектом с использованием Python (3.7) и Django (2.1), в котором я пытаюсь реализовать систему рейтингов.

Примечание: Я много искал и рассмотрел различные связанные вопросы, но не смог найти никакого решения моей конкретной проблемы, поэтому не помечайте это как дублированное, пожалуйста!

У меня есть две модели как:

От models.py :

 class Gig(models.Model):
    CATEGORY_CHOICES = (
        ('GD', 'Graphic amp; Design'),
        ('DM', 'Digital Marketing'),
        ('WT', 'Writing amp; Translation'),
        ('VA', 'Video amp; Animation'),
        ('MA', 'Music amp; Audio'),
        ('PT', 'Programming amp; Tech'),
        ('FL', 'Fun amp; Lifestyle'),
    )

    title = models.CharField(max_length=500)
    category = models.CharField(max_length=255, choices=CATEGORY_CHOICES)
    description = models.CharField(max_length=1000)
    price = models.IntegerField(blank=False)
    photo = models.FileField(upload_to='gigs')
    status = models.BooleanField(default=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.title

class GigReview(models.Model):
    RATING_RANGE = (
        ('1', '1'),
        ('2', '2'),
        ('3', '3'),
        ('4', '4'),
        ('5', '5')
    )
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    gig = models.ForeignKey(Gig, on_delete=models.CASCADE, related_name='rates')
    order = models.ForeignKey(Order, on_delete=models.CASCADE, null=True)
    rating = models.IntegerField(choices=RATING_RANGE,)
    content = models.CharField(max_length=500)

    def __str__(self):
        return self.content
  

От views.py :

 def home(request):
    gigs = Gig.objects.filter(status=True)
    return render(request, 'home.html', {'gigs': gigs})
  

Итак, у каждого Gig есть много отзывов, и я хочу вернуть average рейтинг для каждого концерта в шаблон, как я могу этого добиться?

Ответ №1:

Простая аннотация должна выполнять это за один запрос (а не по одному на Gig при использовании свойства):

 from django.db.models import Avg

gigs = (Gig.objects
    .filter(status=True)
    .annotate(avg_review=Avg('rates__rating'))
)
  

Ответ №2:

Если вы хотите иметь доступ к среднему значению обзора на уровне модели, вы могли бы добавить поле свойства, которое агрегирует среднее значение по связанным моделям в Gig -модели:

 class Gig(models.Model):
    ...

    @property
    def average_rating(self):
        return self.rates.all().aggregate(Avg('rating')).get('rating__avg', 0.00)
        # Change 0.00 to whatever default value you want when there
        # are no reviews.
  

И в шаблоне получить доступ к значению с помощью average_rating .

Комментарии:

1. это отображается как {'rating__avg': 3.5} в шаблоне, как я могу отобразить только значение?

2. @AbdulRehman Я обновил свой ответ, чтобы возвращать только значение. По сути, вы просто добавляете .get('rating__avg', 0.00) в конце агрегирования.