Ответ 1
О, конечно, я забыл о новой поддержке агрегации в Django и ее функциональности annotate
.
Таким образом, запрос может выглядеть так:
Contest.objects.get(pk=id).image_set.annotate(score=Sum('vote__value')).order_by( 'score' )
Допустим, у меня есть следующая модель:
class Contest:
title = models.CharField( max_length = 200 )
description = models.TextField()
class Image:
title = models.CharField( max_length = 200 )
description = models.TextField()
contest = models.ForeignKey( Contest )
user = models.ForeignKey( User )
def score( self ):
return self.vote_set.all().aggregate( models.Sum( 'value' ) )[ 'value__sum' ]
class Vote:
value = models.SmallIntegerField()
user = models.ForeignKey( User )
image = models.ForeignKey( Image )
Пользователи сайта могут представить свои изображения на несколько конкурсов. Тогда другие пользователи могут голосовать за них вверх или вниз.
Все отлично работает, но теперь я хочу отобразить страницу, на которой пользователи могут видеть все вклады в определенный конкурс. Изображения должны быть упорядочены по их оценке. Поэтому я попробовал следующее:
Contest.objects.get( pk = id ).image_set.order_by( 'score' )
Как я и опасался, это не сработает, поскольку 'score'
- это не поле базы данных, которое можно было бы использовать в запросах.
О, конечно, я забыл о новой поддержке агрегации в Django и ее функциональности annotate
.
Таким образом, запрос может выглядеть так:
Contest.objects.get(pk=id).image_set.annotate(score=Sum('vote__value')).order_by( 'score' )
Вы можете написать свой собственный вид в Python очень просто.
def getScore( anObject ):
return anObject.score()
objects= list(Contest.objects.get( pk = id ).image_set)
objects.sort( key=getScore )
Это работает хорошо, потому что мы отсортировали список, который мы собираемся предоставить шаблону.
Уровень db order_by
не может сортировать запрос запроса по методу модели python.
Решение состоит в том, чтобы ввести поле score
в модель Image
и пересчитать его при каждом обновлении Vote
. Некоторая денормализация. Когда вы сможете сортировать по нему.