Is it possible to compute an aggregation (ex.: sum) of an expression (ex.: subtraction) of fields from a related table in a Django ORM query?
For a full example of what I'm trying to achieve, see this working SQL Fiddle. I broke it down into two questions (other one here). In this case, I have a model Sequence
that represents a sequence of numbers, and a model Part
that represent a "link" in this sequence:
Sequence Sequence Sequence Sequence ...
0 5 20 15 ...
|-- Part --|-- Part --|-- Part --|-- ...
Each Part
thus represents a delta, which is the difference between the two values in the sequence. I have a set of (non-contiguous) parts and want to calculate the sum of those deltas. Something like this:
sum([p.after.value - p.before.value for p in Part.objects.filter(...)])
But in a single query (the reason is that I want to use this as a subquery for a more complex one). It's easy to do it in SQL:
select sum(a.value - b.value)
from part p
join sequence a on p.after_id = a.id
join sequence b on p.before_id = b.id
where condition
group by p.other_field;
I don't know how to do it using Django ORM. I can do it for a single value:
Part.objects.filter(condition).aggregate(Sum('before__value')).values()
But not for an expression involving multiple values. Using F()
is not supported yet, so I'm looking for an alternative way. I also looked at this question, which is also about expressions in aggregates, but the accepted answer (using extra
) is not applicable to my case AFAIK, since the fields I'm interested in are not in the same table, but in a related one.
>>> Part.objects.filter(condition).extra(select={
... 'delta':'sum(after__value - before__value)'
... })
DatabaseError: no such column: after__value
Here's a SSCCE, in case anyone want to experiment with it: Download or Browse. It has the same models and data as the SQL fiddle linked above.