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

Django按月份与支付方式分组生成仅含已有数据的报表需求

Django按支付方式分组统计月度交易金额实现方案

一、确认Transactions模型核心字段

假设你的模型包含以下核心字段(已有可直接跳过):

from django.db import models
from django.utils import timezone

class Transactions(models.Model):
    PAYMENT_MODES = (
        ('cash', '现金'),
        ('card', '银行卡'),
        ('online', '线上支付'),
    )
    payment_mode = models.CharField(max_length=20, choices=PAYMENT_MODES)
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    transaction_date = models.DateTimeField(default=timezone.now)

二、修改by_mode视图实现分组统计

利用Django聚合与分组功能,按支付方式、年月维度统计金额,仅保留有数据的月份:

from django.db.models import Sum
from django.db.models.functions import ExtractMonth, ExtractYear
from django.shortcuts import render
from .models import Transactions

def by_mode(request):
    # 按支付方式、年份、月份分组,计算金额总和
    transaction_stats = Transactions.objects.annotate(
        year=ExtractYear('transaction_date'),
        month=ExtractMonth('transaction_date')
    ).values('payment_mode', 'year', 'month').annotate(
        total_amount=Sum('amount')
    ).order_by('year', 'month', 'payment_mode')

    # 整理数据:以(年份,月份)为键,存储对应月份各支付方式的统计值
    monthly_data = {}
    for stat in transaction_stats:
        key = (stat['year'], stat['month'])
        if key not in monthly_data:
            monthly_data[key] = {}
        monthly_data[key][stat['payment_mode']] = stat['total_amount']

    # 按时间顺序排序有数据的月份
    sorted_months = sorted(monthly_data.keys(), key=lambda x: (x[0], x[1]))

    # 获取所有支付方式类型,避免模板遗漏
    payment_modes = dict(Transactions.PAYMENT_MODES).keys()

    context = {
        'monthly_data': monthly_data,
        'sorted_months': sorted_months,
        'payment_modes': payment_modes,
    }
    return render(request, 'transactions/by_mode.html', context)

三、模板实现(仅展示有数据的月份)

以表格样式为例,匹配期望展示效果:

{% load custom_filters %}
<table border="1">
    <thead>
        <tr>
            <th>月份</th>
            {% for mode in payment_modes %}
                <th>{{ mode|title }}</th>
            {% endfor %}
            <th>月度总计</th>
        </tr>
    </thead>
    <tbody>
        {% for year, month in sorted_months %}
            <tr>
                <td>{{ year }}年{{ month }}月</td>
                {% for mode in payment_modes %}
                    <td>{{ monthly_data|get_item:year|get_item:month|get_item:mode|default:"0.00" }}</td>
                {% endfor %}
                <td>
                    {% with month_data=monthly_data|get_item:year|get_item:month %}
                        {{ month_data.values|sum|floatformat:2 }}
                    {% endwith %}
                </td>
            </tr>
        {% endfor %}
    </tbody>
</table>

补充模板自定义过滤器

模板需要get_item和sum两个自定义过滤器,在app目录下创建templatetags/custom_filters.py:

from django import template

register = template.Library()

@register.filter
def get_item(dictionary, key):
    return dictionary.get(key, {})

@register.filter
def sum(values):
    return sum(values) if values else 0

四、关键逻辑说明

  • 仅展示有数据的月份:monthly_data仅包含存在交易统计结果的年月组合,无数据的月份不会进入遍历
  • 分组统计维度:通过ExtractYear和ExtractMonth拆解时间,结合Sum聚合对应维度的交易金额
  • 数据结构优化:将统计结果整理为按年月分组的嵌套字典,方便模板按顺序遍历展示

内容的提问来源于stack exchange,提问作者Jamal A M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 16:27:18