Как группировать и агрегировать с Django

У меня есть довольно простой запрос, который я хотел бы сделать через ORM, но не могу его понять ...

У меня три модели:

Местоположение (место), Атрибут (атрибут, который может иметь место) и Рейтинг (сквозная модель M2M, которая также содержит поле оценки)

Я хочу выбрать некоторые важные атрибуты и иметь возможность ранжировать свои местоположения по этим атрибутам - т.е. более высокий общий балл по всем выбранным атрибутам = лучше.

Я могу использовать следующий SQL, чтобы получить то, что хочу:

select location_id, sum(score) 
    from locations_rating 
    where attribute_id in (1,2,3) 
    group by location_id order by sum desc;

который возвращается

 location_id | sum 
-------------+-----
          21 |  12
           3 |  11

Самое близкое, что я могу получить с ORM, это:

Rating.objects.filter(
    attribute__in=attributes).annotate(
    acount=Count('location')).aggregate(Sum('score'))

Который возвращается

{'score__sum': 23}

т.е. сумма всех, не сгруппированных по местоположению.

Каким-либо образом обойти это? Я мог бы выполнить SQL вручную, но предпочел бы использовать ORM, чтобы все было согласовано.

Спасибо


person Guy Bowden    schedule 15.11.2012    source источник
comment
Возможный дубликат Как запросить как GROUP BY в django?   -  person Aaron McMillin    schedule 25.09.2017


Ответы (2)


Попробуй это:

Rating.objects.filter(attribute__in=attributes) \
    .values('location') \
    .annotate(score = Sum('score')) \
    .order_by('-score')
person Aamir Adnan    schedule 15.11.2012
comment
хммм - аннотировать, а не агрегировать - почему? - person Guy Bowden; 16.11.2012
comment
aggregate - для полного набора результатов, annotate - для отдельных (сгруппированных) строк. - person Bouke; 16.01.2013
comment
кто-нибудь знает, как обойти 'dict' object has no attribute '_meta' с таким QuerySet? - person maciek; 16.09.2016
comment
Привет @Aamir, у меня похожая проблема, можешь посмотреть? ссылка здесь - person Ermir Beqiraj; 01.04.2018
comment
Возвращает что-то вроде [{"location": 53, "score": 100}, {"location": 54, "score": 104}] - person Irvan; 01.06.2018

Вы можете попробовать это.

Rating.objects.values('location_id').filter(attribute__in=attributes).annotate(sum_score=Sum('score')).
person Srinivas Reddy Thatiparthy    schedule 15.11.2012