【问题标题】:Django cumulative sum in model (sqlite)模型中的Django累积总和(sqlite)
【发布时间】:2022-01-14 16:02:40
【问题描述】:

我的模型是:

class transaction(models.Model):
    transactiondate = models.DateField()
    category = models.ForeignKey(category, on_delete=models.PROTECT, default=0)
    details = models.CharField(max_length=200, null=True)
    amount = models.DecimalField(decimal_places=2, max_digits=10)
    accountid = models.ForeignKey(account, on_delete=models.PROTECT)

我使用原始 SQL 查询获得每个日期的累计总数:

def cumulativebalance():
        query = """SELECT id, transactiondate,
            SUM("amount") 
            OVER (ORDER BY transactiondate) AS "cumsum" 
            FROM "transactions_transaction"
            GROUP BY transactiondate 
            ORDER BY transactiondate ASC, "cumsum" ASC
            """
        return balance = transaction.objects.raw(query)

这确实返回了我正在寻找的输出。我的问题是 Django 中是否有一种方法可以将其合并到我的模型中,而不是将其作为原始 SQL 使用?

我尝试过的

我确实找到了以前的similar question,并且我已经根据自己的模型调整了答案:

test = transaction.objects.annotate(
            cumsum=Func(
                Sum('amount'), 
                template='%(expressions)s OVER (ORDER BY %(order_by)s)', 
                order_by="transactiondate"
            ) 
        ).values('transactiondate', 'cumsum').order_by('transactiondate', 'cumsum')

但这给了我一个错误:OperationalError at /transactions/ near "OVER": 语法错误。我不明白这在告诉我什么。

生成的 SQL 显示在回溯中。我最好的猜测是它应该是 OVER 之后的 PARTITION BY 而不是 ORDER BY,但我不知道如何从我的 python 代码中改变它。

('SELECT "transactions_transaction"."transactiondate", '
 'CAST(CAST(SUM("transactions_transaction"."amount") AS NUMERIC) OVER (ORDER '
 'BY transactiondate) AS NUMERIC) AS "cumsum" FROM "transactions_transaction" '
 'GROUP BY "transactions_transaction"."id", '
 '"transactions_transaction"."transactiondate", '
 '"transactions_transaction"."category_id", '
 '"transactions_transaction"."details", "transactions_transaction"."amount", '
 '"transactions_transaction"."accountid_id" ORDER BY '
 '"transactions_transaction"."transactiondate" ASC, "cumsum" ASC')

【问题讨论】:

    标签: django sqlite


    【解决方案1】:

    由于,可以使用Window expressions [Django-doc]

    from django.db.models import F, Sum, Window
    
    transaction.objects.annotate(
        cumsum=Window(Sum('amount'), order_by=F('transactiondate').asc())
    ).order_by('transactiondate', 'cumsum')

    由此产生的transaction 对象将具有一个额外的属性.cumsum


    注意:Django 中的模型是用 PascalCase 编写的,而不是 snake_case, 因此您可能需要将模型从 transaction 重命名为 Transaction

    【讨论】:

      猜你喜欢
      • 2017-09-16
      • 1970-01-01
      • 2021-01-18
      • 1970-01-01
      • 2019-02-15
      • 2020-04-18
      • 2022-01-27
      • 2021-06-08
      • 2018-07-02
      相关资源
      最近更新 更多