Aggregation of an expression in Django query spanning multiple tables

大城市里の小女人 提交于 2019-12-13 02:35:12

问题


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.


回答1:


Now that 1.8 implemented support for F expressions in aggregate, the answer became straightforward:

Part.objects.filter(condition).aggregate(sum=Sum(F('after__value')-F('before__value'))).values()


来源:https://stackoverflow.com/questions/15453662/aggregation-of-an-expression-in-django-query-spanning-multiple-tables

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!