#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)
в конце агрегирования.