能否通过单条Django查询获取指定人员分月销售总额?
问题解答
需求明确
需按月份统计John和Mary的销售总额(求和),忽略其他销售人员的数据;日期以「年份-月份」格式按时间从旧到新排序,哪怕某人员在对应月份没有销售额(总额为0),也要显示该记录。
给定信息
示例输出数据:
[ ["19-Nov", "John", 511.97], ["19-Nov", "Mary", 0], ["19-Dec", "John", 568.21], ["19-Dec", "Mary", 1542.08], ["20-Jan", "John", 621.20], ["20-Jan", "Mary", 401.06], ["20-Feb", "John", 621.39], ["20-Feb", "Mary", 0], ["20-Mar", "John", 0], ["20-Mar", "Mary", 871.14], ["20-Apr", "John", 604.25], ["20-Apr", "Mary", 653.34], ["20-May", "John", 584.94], ["20-May", "Mary", 1218.43], ]
Django模型定义:
class Sellers(models.Model): date = models.DateField() name = models.CharField(max_length=300) value = models.DecimalField(max_digits=19, decimal_places=2)
核心答案
完全可以用单条Django查询搭配聚合、条件表达式实现需求,但要注意:必须先确定要统计的完整月份范围——因为要显示0销售额的记录,哪怕某月份里John或Mary没有对应数据。
实现步骤与代码
- 先拿到所有需要统计的月份:从数据库中提取所有涉及的月份(或者指定固定范围),确保没有遗漏。
- 单条查询完成分组与条件求和:按月份分组,分别计算John和Mary的销售额,无数据时返回0。
- 转换为目标格式:把查询结果拆分成示例要求的二维数组结构。
from django.db.models import Sum, Case, When, Value, DecimalField from django.db.models.functions import TruncMonth # 1. 获取数据库中所有涉及的月份(按时间升序) all_target_months = Sellers.objects.dates('date', 'month', order='ASC') # 2. 核心查询:按月份分组,统计John和Mary的销售额(无数据则为0) monthly_totals = Sellers.objects.filter(name__in=['John', 'Mary']) \ .annotate(month=TruncMonth('date')) \ .values('month') \ .annotate( john_sum=Sum( Case(When(name='John', then='value'), default=Value(0), output_field=DecimalField()) ), mary_sum=Sum( Case(When(name='Mary', then='value'), default=Value(0), output_field=DecimalField()) ) ) \ .order_by('month') # 3. 转换为示例要求的格式 result = [] # 把查询结果转成字典,方便快速查找对应月份的数据 month_dict = {item['month']: item for item in monthly_totals} for month in all_target_months: # 格式化月份为「年份-月份」格式(如"19-Nov") month_str = month.strftime("%y-%b") # 取对应数据,无则为0 john_val = month_dict.get(month, {}).get('john_sum', 0) mary_val = month_dict.get(month, {}).get('mary_sum', 0) # 添加到结果数组 result.append([month_str, 'John', john_val]) result.append([month_str, 'Mary', mary_val])
关键细节说明
TruncMonth:Django内置的日期函数,把date字段截断到月份级别,用来实现按月份分组。Case/When + Sum:精准筛选对应人员的销售额求和,没有数据时用default=Value(0)返回0,满足“即使销售额为0也需显示”的要求。- 遍历所有目标月份:确保每个月份都能生成John和Mary的记录,不会因为某人员当月无数据就漏掉条目。
内容的提问来源于stack exchange,提问作者Felipe Dourado
相关产品推荐
相关产品推荐

