Django:如何获取每位销售者每日的首条销售记录
获取每位销售者每日首条销售记录的实现方案
嗨,这个需求用Django ORM就能优雅解决,我给你两种靠谱的实现方式,你可以根据自己的场景选择:
方法一:使用窗口函数(推荐,高效简洁)
窗口函数是Django 2.0+支持的特性,非常适合这种「分组取Top N」的场景。我们可以给每个销售者+日期的分组里的记录按时间排序,然后取第一条:
首先导入需要的函数:
from django.db.models import F, Window from django.db.models.functions import RowNumber, TruncDate
然后编写查询逻辑:
# 1. 先把DateTime类型的Date字段截断为纯日期(如果你的Date是DateField可以跳过TruncDate) # 2. 按「销售者+日期」分区,每个分区内按销售时间升序排序,给每条记录编行号 sales_with_row_num = Sales.objects.annotate( sale_date=TruncDate('Date'), row_num=Window( expression=RowNumber(), partition_by=[F('Saler'), TruncDate('Date')], order_by=F('Date').asc() ) ) # 筛选出行号为1的记录,就是每个销售者当天的第一条销售记录 first_sales_per_day = sales_with_row_num.filter(row_num=1)
关键说明:
- TruncDate('Date'):如果你的
Date字段是DateTimeField,这个函数会把时间部分去掉,只保留年月日,确保同一天的记录会被分到同一个组里;如果Date本身就是DateField,直接用F('Date')代替TruncDate('Date')即可。 - RowNumber():每个分区内的记录会按
Date升序排列,第一条记录的行号为1,后续依次递增。如果同一天同一销售者有多个记录在同一秒创建,你可以把RowNumber()换成Rank(),这样同时间的记录都会得到行号1,能保留所有「并列第一条」的记录。
方法二:子查询关联(兼容旧版Django)
如果你的Django版本低于2.0,或者更习惯用子查询的方式,可以这么写:
from django.db.models import Subquery, OuterRef # 子查询:找到每个销售者在对应日期的第一条销售记录ID subquery = Sales.objects.filter( Saler=OuterRef('Saler'), Date__date=OuterRef('Date__date') # 同样,DateField的话直接用Date=OuterRef('Date') ).order_by('Date').values('id')[:1] # 主查询:筛选出所有符合条件的记录 first_sales_per_day = Sales.objects.filter(id__in=Subquery(subquery))
这个方法的逻辑是先通过子查询定位每个销售者每天最早的那条记录的ID,再用主查询取出完整的记录。
注意事项
- 确保
Saler字段是可分组的类型(比如外键、CharField、IntegerField),否则分组会出错。 - 如果你的
Date字段没有索引,建议给它加个联合索引(Saler+Date),能大幅提升查询效率,尤其是数据量大的时候。
内容的提问来源于stack exchange,提问作者MichaelS
相关产品推荐
相关产品推荐

