#django #django-models #django-orm
Вопрос:
Я застрял в этой, очевидно, основной проблеме, мне кажется, что мне не хватает чего-то очевидного, чтобы заставить это работать должным образом.
Моя модель бд является:
class Review(models.Model):
SCORE_CHOICES = [(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5')]
user = models.ForeignKey(get_user_model(), related_name="reviews_by_user", on_delete=models.CASCADE)
recipe = models.ForeignKey(Recipe, related_name="reviews_by_recipe", on_delete=models.CASCADE)
score = models.IntegerField(choices=SCORE_CHOICES)
date_created = models.DateTimeField(default=timezone.now)
def __str__(self):
return f"{self.user} rated {self.recipe} with {self.score}"
class Meta:
ordering = ['-date_created']
Я пытаюсь сгруппироваться по рецепту, подсчитывая средний балл обзора.
Этот подход кажется прекрасным, но он не работает:
Review.objects.values('recipe').annotate(Avg('score'))
в результате я получаю:
<QuerySet [{'recipe': 1, 'score__avg': 5.0}, {'recipe': 1, 'score__avg': 5.0}, {'recipe': 2, 'score__avg': 4.0}, {'recipe': 2, 'score__avg': 3.0}, {'recipe': 5, 'score__avg': 3.0}, {'recipe': 5, 'score__avg': 2.0}]>
Что для меня абсолютно странно. Он должен группировать рецепты, но вместо этого он подсчитывает среднее значение для каждой строки. Я просмотрел документацию по агрегированию Django, но не могу найти никаких ограничений или специальных положений, которые могли бы помочь понять, чего мне не хватает.
Пожалуйста, дайте мне знать, если у кого-нибудь есть представление о том, что происходит.
Ответ №1:
Решено!
.метод order_by() в конце концов «завершает» такую группировку
так:
Review.objects.values('recipe').annotate(Avg('score')).order_by()
Результат:
<QuerySet [{'recipe': 1, 'score__avg': 5.0}, {'recipe': 2, 'score__avg': 3.5}, {'recipe': 5, 'score__avg': 2.5}]>
Комментарии:
1. Не «завершается», скажем, потому, что порядок по умолчанию в вашей модели мешает здесь группе по ( docs.djangoproject.com/en/3.1/topics/db/aggregation/… ). Если вы обновитесь до Django 3.2, этот вызов
order_by
больше не понадобится.