2016-08-18 1 views
4

У меня есть Donation модель определяется как:Джанго запрос, среднее количество отчетливый

Donation 
    project = models.ForeignKey(Project) 
    user = models.CharField() 

Каждый пользователь может пожертвовать несколько раз для любого проекта, поэтому в БД я могу иметь следующее:

Donation 
------------------- 
project | user 
------------------- 
1  | A 
2  | A 
3  | A 
1  | B 
2  | B 
2  | C 

Теперь мне нужно вычислить среднее значение отдельного проекта для каждого пользователя, в этом случае оно будет:

A: 3 
B: 2 
C: 1 
=> (3 + 2 + 1)/3 = 2 

То, что я до сих пор является следующее:

distinct_pairs = Donation.objects.order_by('project') 
     .values('user', 'project') 
     .distinct() 

Это дает мне список distincts project/user пар, что я могу работать с в питона.

Хотелось бы узнать, есть ли способ query-only?

Моя установка:

  • Джанго 1,8
  • PostgreSQL
+0

Просто интересно - почему вы сделали пользовательским полем вместо внешнего ключа для пользовательской модели? Поле Char как пользователь не похоже на лучшую практику, imo –

+0

Это потому, что это не «настоящий» пользователь, это в основном для упрощения примера. – nobe4

ответ

4

Вам не нужно суммировать значения для среднего, вы можете просто рассчитывать различные значения и разделить на число различных пользователей. Также order_by является избыточным, поскольку нам нужны только цифры.

distinct_pairs_count = Donation.objects.values('user', 'project').distinct().count() 

distinct_users_count = Donation.objects.values('user').distinct().count() 

average = distinct_pairs_count/float(distinct_users_count) # in Python 2 
average = distinct_pairs_count/distinct_users_count   # in Python 3 

EDIT: сделать это один QuerySet

Я думаю, что вы можете достичь этого, один запрос, но я не могу проверить это прямо сейчас:

from django.db.models import Count, Avg 

average = Donation.objects.values('user', 'project') 
      .annotate(num_projects=Count('project', distinct=True)) 
      .aggregate(Avg('num_projects')) 

См: aggregating annotations in 1.8

+0

Я не уверен, что это сработает. Рассмотрим случай, когда 5 пользователей жертвуют один и тот же проект один раз. 'distinct_pairs_count' будет 5, а' distinct_projects_count' будет 1, средний будет 5, а не 1 ... – nobe4

+1

@ nobe4 да, извините, я имел в виду разделить число пользователей, а не проекты. Я обновил свой ответ. – akarilimano

+0

Это хороший обходной путь, я буду использовать его, пока не найду только запрос (если таковой существует), спасибо. – nobe4