带有原始查询的Django RawQuerySet减法

时间:2019-08-10 17:06:35

标签: django orm

我正在postgres中尝试此查询,

select
  (SELECT sum(amount)
   FROM expense_expense
   WHERE flow='INFLOW')-
  (SELECT sum(amount)
   FROM expense_expense
   WHERE flow='OUTFLOW') AS balance;

摆脱困境

balance|
-------|
6370.77| 

但是当我尝试使用Django RawQuerySet时,它要求的是主键

In [168]: r = Expense.objects.raw("select(select sum(amount) FROM expense_expense  where flow='INFLOW') - (select sum(amount) FROM expense_expense  where flow='OUTFLOW') as balance;")                                                          

In [169]: r.columns                                                                                                                                                                                                                             
Out[169]: ['balance']

In [170]: r[0]                                                                    

---------------------------------------------------------------------------
InvalidQuery                              Traceback (most recent call last)
<ipython-input-170-8418cdc095ae> in <module>
----> 1 r[0]

~/Desktop/workspace/projects/python/django/expenditure/venv/lib/python3.7/site-packages/django/db/models/query.py in __getitem__(self, k)
   1433 
   1434     def __getitem__(self, k):
-> 1435         return list(self)[k]
   1436 
   1437     @property

~/Desktop/workspace/projects/python/django/expenditure/venv/lib/python3.7/site-packages/django/db/models/query.py in __iter__(self)
   1393 
   1394     def __iter__(self):
-> 1395         self._fetch_all()
   1396         return iter(self._result_cache)
   1397 

~/Desktop/workspace/projects/python/django/expenditure/venv/lib/python3.7/site-packages/django/db/models/query.py in _fetch_all(self)
   1380     def _fetch_all(self):
   1381         if self._result_cache is None:
-> 1382             self._result_cache = list(self.iterator())
   1383         if self._prefetch_related_lookups and not self._prefetch_done:
   1384             self._prefetch_related_objects()

~/Desktop/workspace/projects/python/django/expenditure/venv/lib/python3.7/site-packages/django/db/models/query.py in iterator(self)
   1408             model_init_names, model_init_pos, annotation_fields = self.resolve_model_init_order()
   1409             if self.model._meta.pk.attname not in model_init_names:
-> 1410                 raise InvalidQuery('Raw query must include the primary key')
   1411             model_cls = self.model
   1412             fields = [self.model_fields.get(c) for c in self.columns]

InvalidQuery: Raw query must include the primary key

In [171]:

有什么我想念的还是需要做的,请让我知道如何实现。这将对我非常有帮助。预先感谢。

1 个答案:

答案 0 :(得分:1)

您不能对此类聚合使用原始查询,因为.raw(..) queries [Django-doc]用于检索模型对象:

  

raw()管理器方法可用于执行返回模型实例的原始SQL查询。

但是首先根本不需要使用原始查询。实际上,您应该避免这种情况,除非没有合理的选择使用ORM。

from django.db.models import Q, Sum

Expense.objects.aggregate(
    balance=Sum('amount', filter=Q(flow='INFLOW'))-Sum('amount', filter=Q(flow='OUTFLOW'))
)

这将返回一个字典,其中包含一个名为'balance'的键,该键映射到天平。

如果流量不仅限于'INFLOW''OUTFLOW',可以通过首先过滤查询集来稍微提高性能:

from django.db.models import Q, Sum

Expense.objects.filter(
    flow__in=('INFLOW', 'OUTFLOW')
).aggregate(
    balance=Sum('amount', filter=Q(flow='INFLOW'))-Sum('amount', filter=Q(flow='OUTFLOW'))
)