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

Django按日期范围查询时如何基于balance字段生成累计余额CumBalance列

问题原因

你之前的实现方式存在以下问题:

  • annotate(cumbalance =Sum('balance')) 是对单行的balance字段求和,计算结果和原balance字段完全一致,无法得到累计值
  • aggregate(Sum('balance')) 会直接返回整个查询集的总余额数值,无法和每一行明细数据对应

解决方案1:数据库层面实现(推荐,性能更高)

Django 2.0及以上版本支持窗口函数,可以直接在SQL层面计算累计值,适合数据量较大的场景:
首先导入需要的方法:

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

修改视图中的查询代码:

def partyDetails(request,pk):
    form = DateRangeForm()
    cumulative_balance = []
    if request.method == 'POST':
        form = DateRangeForm(request.POST)
        if form.is_valid():
            start = form.cleaned_data['start_date']
            end = form.cleaned_data['end_date']
            cumulative_balance = PurchasePayment.objects.filter(
                vendor=pk,
                date__range=(start, end)
            ).order_by('date', 'id').annotate( # 按日期+id排序,避免同一天数据顺序错乱
                cumbalance=Window(
                    expression=Sum('balance'),
                    order_by=[F('date').asc(), F('id').asc()],
                    frame=Window.rows_between(Window.UNBOUNDED_PRECEDING, Window.CURRENT_ROW)
                )
            )
        else:
            return redirect('party_ledger')
    return render(request, 'purchase/party_details.html', {
        'dateform':form, 
        'cumbal':cumulative_balance,
        'name':pk
    })

解决方案2:Python层面遍历实现(兼容低版本Django,适合小数据量)

如果Django版本不支持窗口函数,或者查询数据量很小,可以直接在Python代码中遍历计算累计值:

def partyDetails(request,pk):
    form = DateRangeForm()
    cumulative_balance = []
    if request.method == 'POST':
        form = DateRangeForm(request.POST)
        if form.is_valid():
            start = form.cleaned_data['start_date']
            end = form.cleaned_data['end_date']
            payment_list = PurchasePayment.objects.filter(
                vendor=pk,
                date__range=(start, end)
            ).order_by('date', 'id')
            cum_total = 0
            for item in payment_list:
                cum_total += item.balance
                item.cumbalance = cum_total
                cumulative_balance.append(item)
        else:
            return redirect('party_ledger')
    return render(request, 'purchase/party_details.html', {
        'dateform':form, 
        'cumbal':cumulative_balance,
        'name':pk
    })

模板渲染

两种方案最终返回的cumbal对象都可以直接在模板中调用cumbalance属性展示累计余额:

{% for item in cumbal %}
<tr>
    <td>{{ item.amount }}</td>
    <td>{{ item.payment }}</td>
    <td>{{ item.balance }}</td>
    <td>{{ item.cumbalance }}</td>
</tr>
{% endfor %}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 03:42:01