2010-03-20 5 views
2

Я пытаюсь вычислить среднее значение поля по различным подмножествам набора запросов.Агрегация нескольких моделей - Django

Player.objects.order_by('-score').filter(sex='male').aggregate(Avg('level')) 

Это прекрасно работает!


Но ... если я пытаюсь вычислить его для 50 лучших игроков это не работает.

Player.objects.order_by('-score').filter(sex='male')[:50].aggregate(Avg('level')) 

Этот последний возвращает тот же результат, что и запрос над ним, что неверно.


Что я делаю неправильно?

Помощь была бы очень признательна!

+0

Вы хотите получить средний уровень для «топ-50 игроков мужского пола» или «мужчин-игроков в топ-50»? Ваш код предлагает «топ-50 игроков-мужчин», но в вашем описании говорится только «топ-50 игроков». – istruble

ответ

4
topfifty = Player.objects.order_by('-score')[:50] 
Player.objects.filter(sex='male',pk__in=topfifty).aggregate(avglevel=Avg('level')) 

Редактировать: я не тестировал это, но думаю, вы поняли, куда я иду.

topfifty = Player.objects.order_by('-score')[:50] 
ids = [] 
for t in topfifty: 
    ids += [t.id] 

Player.objects.filter(sex='male',pk__in=ids).aggregate(avglevel=Avg('level')) 

Это хакерское, но лучшее, что я могу придумать. возможно, рассмотреть фильтрацию для мужчин и взять 50 лучших мужчин вместо этого, который берет верхнюю пядь, а затем отфильтровывает самцов.

+0

@Brandon: Я смущен ... это возвращает средний уровень для каждого игрока? Каждый игрок имеет 1 уровень поля, я пытаюсь вычислить среднее значение по группе игроков! В любом случае спасибо за ответ. :) – RadiantHex

+0

ах, я настроюсь соответствующим образом. –

+0

@Brandon: спасибо !! Отлично! : D – RadiantHex

-1

Хм. Документы говорят, что

«Нарезка. Как описано в разделе Ограничение запросов QuerySet, QuerySet можно нарезать, используя синтаксис массива Python. Обычно нарезка QuerySet возвращает другой (неоцененный) QuerySet, но Django будет выполнять запрос базы данных, если вы используете параметр «шаг» синтаксиса среза ». http://docs.djangoproject.com/en/dev/ref/models/querysets/

Так что я хотел бы попробовать

Player.objects.order_by('-score').filter(sex='male')[0:50:1].aggregate(Avg('level')) 
+0

@Vicki: спасибо. К сожалению, он возвращает ** Объект 'list' не имеет атрибута 'aggregate' ** :) Было бы здорово, если бы это сработало! – RadiantHex

3

Разбейте задачу на два логических шагов; определить целевой набор, выполнить совокупный расчет.

top50_male_players = Player.objects.filter(sex='male').order_by('-score')[:50] 
result = Player.objects.filter(pk__in=top50_male_players).aggregate(Avg('level')) 

Благодаря ленивой оценке QuerySet он будет выполняться в одной операции с БД. Вы можете играть с этим в оболочке, чтобы проверить количество запросов.

> from django.db import connection 
> connection.queries = [] 
> top50_male_players = Player.objects.filter(sex='male').order_by('-score')[:50] 
> len(connection.queries) 
0 
> result = Player.objects.filter(pk__in=top50_male_players).aggregate(Avg('level')) 
> len(connection.queries) 
1 
> result 
{'level__avg': <some number>} 
> len(connection.queries) 
1 
+0

@istruble: спасибо за ваш ответ! к сожалению, я не знаю, почему ** pk__in = queryset ** не возвращает правильные результаты. Но действительно работает, если я создаю массив идентификаторов вместо этого. – RadiantHex

+0

Это очень странно. Используете ли вы что-то другое, кроме filter() order_by() и []/slice, чтобы получить значение 'queryset'? Я еще раз посмотрю, если вы вставляете строку, которую используете для создания 'queryset', в другом комментарии. – istruble

Смежные вопросы