Как суммировать с условием в кверисете Django

Я пытаюсь суммировать запрос Django с условием. Предположим, у меня есть некоторые данные следующего вида:

| Name | Type |
---------------
| a    | x    |
| b    | z    |
| c    | x    |
| d    | x    |
| e    | y    |
| f    | x    |
| g    | x    |
| h    | y    |
| i    | x    |
| j    | x    |
| k    | x    |
| l    | x    |

Эти типы являются строковыми и имеют значения, например x = 1, y = 25, z = -3

Как суммировать все значения без цикла? В настоящее время используется цикл.

data = A.objects.all()
sum = 0
mapp = {'x': 1, 'y': 25, 'z': -3}
for datum in list(data):
    sum = sum + mapp[datum.type]
print(sum)

Вы можете сократить это следующим образом:

sum(mapp.get(o['Type'],0) for o in data)

или проще, если вы доверяете данным, что они имеют все допустимые типы:

sum(mapp[o['Type']] for o in data)

(Не доверяйте данным)

Если отображение x = 1, y = 25 и т.д... происходит из другой таблицы, вы можете использовать некоторые SQL вуду, чтобы позволить базе данных обрабатывать суммирование за вас. В противном случае вам придется (тем или иным способом) перебирать все результаты и суммировать их.

Теоретически можно также просто подсчитать количество x, y и z в таблице и получить sum = x*count_of_x + y*count_of_y + z*count_of_z, исходя из того, как структурирован пример.

Для выполнения вычисления внутри базы данных используйте Queryset.aggregate() с агрегатным выражением, которое использует Case/When:

from django.db.models import Sum, Case, When

A.objects.all().aggregate(
    amount=Sum(Case(
        When(type="x", then=1), 
        When(type="y", then=25), 
        When(type="z", then=-3),
        default=0,
        output_field=FloatField()
    ))
)
Вернуться на верх