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
相关产品推荐
相关产品推荐

