我的模型包括投资组合,控股公司和公司。每个投资组合都有很多控股公司,每个控股公司都是一家公司(公司可能与许多控股公司有关)。
投资组合 - <持有> - 公司
我希望投资组合查询返回投资组合中控股数量与公司价值之和的总和。
简化型号:
class Portfolio(model):
some fields
class Company(model):
closing = models.DecimalField(max_digits=10, decimal_places=2)
class Holding(model):
portfolio = models.ForeignKey(Portfolio)
company = models.ForeignKey(Company)
num_shares = models.IntegerField(default=0)
我希望能够查询:
Portfolio.objects.some_function()
并使用Portfolio的值注释每一行,其中值等于相关Company.closing和Holding.num_shares的乘积之和。比如:
annotate(value=Sum('holding__num_shares * company__closing'))
我还希望获得一个摘要行,其中包含所有用户投资组合的价值总和,以及持有数量的计数。比如:
aggregate(Sum('holding__num_shares * company__closing'), Count('holding__num_shares'))
我希望对单个投资组合有一个类似的汇总行,即每个持股的价值总和,以及投资组合中持股总数的计数。
我设法使用extra
:
return self.extra(
select={
'value': 'select sum(h.num_shares * c.closing) from portfolio_holding h '
'inner join portfolio_company as c on h.company_id = c.id '
'where h.portfolio_id = portfolio_portfolio.id'
}).annotate(Count('holding'))
但这很丑陋,而且由于显而易见的原因,额外的东西似乎不受欢迎。
我的问题是:是否有更多Djangoistic方法来基于多个字段和相关表来汇总和注释查询?
这两个选项似乎朝着正确的方向发展:
Portfolio.objects.annotate(Sum('holding__company__closing'))
(即,这演示了相关表中字段的注释/聚合)
Holding.objects.annotate(Sum('id', field='num_shares * id'))
(这演示了对两个字段的乘积的注释/聚合)
但是如果我尝试将它们组合起来:例如
Portfolio.objects.annotate(Sum('id', field='holding__company__closing * holding__num_shares'))
我收到错误:"没有这样的专栏' holding__company__closing'。
到目前为止,我已经查看了以下相关问题,但它们似乎都没有捕获到这个确切的问题: Annotating django QuerySet with values from related table Product of two fields annotation
我只需要咬紧牙关并使用raw / extra吗?我希望Django ORM能够证明ORM实际上只是为简单的查询/模型设计的规则是例外,除了最基本的查询/模型之外的任何东西都需要严格的粗略的跳舞,或者走出抽象,这有点挫败了目的......
提前致谢!