2016-06-24 2 views
3

Я пытаюсь вычислить эквивалент SELECT SUM(...) FROM ... GROUP BY .... Вот упрощенная аналогия:Возможно ли объединение по агрегированному запросу с помощью django ORM?

Скажем Salesperson объекты продают вещи и получить комиссию на полях они производят через каждый Sale:

sp = Salesperson.objects.get(pk=1) 
my_sales = Sale.objects.filter(fk_salesperson=sp) 

#calculate commission owing to sp 
commission = 0 
for sale in my_sales: 
    commission += sp.commission_rate\ 
        * (sale.selling_price - sale.cost_price) 

Этот последний цикл может быть сделано что-то вроде:

.annotate(commission= (F('selling_price')-F('cost_price'))\ 
          * sp.commission_rate) 

Но могу ли я затем агрегировать запрос для всех объектов Salesperson? То есть Я хочу знать каждую комиссию продавца (т. Е. Примерно SELECT SUM((sale_price-cost_price) * commission_rate) FROM Sales GROUP BY Salesperson). Я мог бы сделать что-то вроде ниже, но я пытаюсь сделать это с ОРМ:

commissions = [] 
salespeople = Salesperson.objects.all() 
for sp in salespeople: 
    data = Sale.objects.filter(fk_salesperson=sp)\ 
     .annotate(salesperson=F('sp__email')\ 
     .annotate(commission= (F('selling_price')-F('cost_price'))\ 
           * sp.commission_rate) 
    commissions.append(data) 

Есть ли способ сделать это с помощью одного запроса (что делает сервер отчетов дб сделать работу), а не делать это на моем сервере приложений?

ответ

2

Агрегатная функция Sum() доступна в django.db.models, и вы можете использовать связанные поля в выражении F.

from django.db.models import F, Sum 

Sales.objects.values('salesperson__id').annotate(commission=Sum(
    (F('selling_price') - F('cost_price')) * F('salesperson__commission_rate') 
)) 
+0

Спасибо, Unfortuneately ваше решение не понимает сути примера question.The намеренно построено таким образом, что не существует связанное с поля «' sales'»в модели' Salesperson'. (Это логично: продажа должна быть иностранным ключом, указывающим на продавца, а не наоборот). Цель этого примера - найти решение для запроса в 'Sale', а затем группировать по внешнему ключу соответствующего поля в' Sale' под названием '' fk_salesperson'. – Escher

+1

Там ** есть ** отношение, хотя и неявное. Это обратное отношение. https://docs.djangoproject.com/en/1.9/topics/db/queries/#backwards-related-objects –

+0

Я бы рекомендовал установить ['related_name'] (https://docs.djangoproject.com/en /1.9/ref/models/fields/#django.db.models.ForeignKey.related_name) для каждого ForeignKey, чтобы дать ему значимое имя. Если вы его не установили, я думаю, что это будет 'sale_set__' вместо' sales__'. –

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