You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Django ORM结合SQLite实现相邻行累加计算余额

使用Django ORM计算累计余额(Running Balance)

先明确你的需求:现有一组包含id和amt的交易数据,需要为每一行计算到当前行为止的累计余额balance,示例如下:

原始数据

idamt
1100
2-50
3100
4-100
5200

期望输出

idamtbalance
1100100
2-5050
3100150
4-10050
5200250

下面介绍两种实现方式,优先推荐第一种数据库层面的高效方案:


方法一:使用Django窗口函数(推荐,Django 2.0+)

如果你的数据库支持窗口函数(比如PostgreSQL、MySQL 8.0+、SQLite 3.25+),这是最优解——直接让数据库完成累计计算,性能比Python层面处理好得多。

假设你的Django模型定义如下:

from django.db import models

class Transaction(models.Model):
    amt = models.IntegerField()
    # 注意:id是Django默认的自增主键,不需要额外定义

你可以通过Window和Sum来实现累计余额的计算:

from django.db.models import Sum, F
from django.db.models.window import Window

# 查询并添加累计余额字段
transactions = Transaction.objects.annotate(
    balance=Window(
        expression=Sum('amt'),
        order_by=F('id').asc(),  # 按id升序累加,确保顺序正确
        frame=Window.RANGE,
        start=Window.UNBOUNDED_PRECEDING,  # 从第一行开始
        end=Window.CURRENT_ROW  # 到当前行结束
    )
).order_by('id')

代码解释

  • Window指定了计算的窗口范围:从数据集的第一行(UNBOUNDED_PRECEDING)到当前行(CURRENT_ROW)
  • Sum('amt')对窗口内的amt字段求和,得到累计余额
  • order_by=F('id').asc()保证按id的顺序累加,避免结果混乱

查询结果中的每个Transaction对象都会新增一个balance属性,对应累计值。


方法二:Python层面遍历计算(适合小数据集)

如果你的数据库不支持窗口函数,或者数据量很小,可以在查询后用Python循环计算累计余额:

# 先按id排序查询所有数据
transactions = Transaction.objects.order_by('id').all()

# 遍历计算累计余额
current_balance = 0
for tx in transactions:
    current_balance += tx.amt
    tx.balance = current_balance  # 给对象新增一个临时属性

这种方法的缺点是:当数据量很大时,需要把所有数据加载到内存中处理,性能不如窗口函数方案。


内容的提问来源于stack exchange,提问作者Russell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:52:34