Django:统计指定日期范围内唯一起讫点对的行程次数
解决行程监控应用的起点-终点对统计需求
嘿,我来帮你搞定这个行程统计的需求!首先先补全一下你的模型(看起来你没写完Trip的关联字段,我假设是这样的):
class Location(models.Model): name = models.CharField(max_length=50, unique=True) # 你的其他字段... class Trip(models.Model): ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE) # 假设Ticket是你定义的票据模型 origin = models.ForeignKey(Location, on_delete=models.CASCADE, related_name='origin_trips') destination = models.ForeignKey(Location, on_delete=models.CASCADE, related_name='destination_trips') trip_date = models.DateField() # 核心:用来筛选日期范围的字段,用DateTimeField也一样能用 # 你的其他字段...
接下来分两种常见场景给你解决方案:
场景1:区分往返行程(A→B和B→A算不同路线)
用Django ORM的values()+annotate()就能轻松实现分组统计,还能直接关联获取地点名称:
from django.db.models import Count from datetime import date # 定义你要统计的日期范围 start_date = date(2024, 1, 1) end_date = date(2024, 12, 31) # 执行统计:筛选日期→按起点+终点分组→统计每组行程数 trip_stats = Trip.objects.filter( trip_date__range=(start_date, end_date) ).values( 'origin__name', 'destination__name' # 直接用地点名称分组,不用后续再查Location ).annotate( trip_count=Count('id') # 统计每组的行程数量 ).order_by('-trip_count') # 可选:按行程数从多到少排序
遍历结果的示例:
for stat in trip_stats: print(f"从{stat['origin__name']}到{stat['destination__name']}: {stat['trip_count']}次行程")
如果需要保留地点的ID(比如后续要做关联操作),可以调整values()的参数:
trip_stats = Trip.objects.filter( trip_date__range=(start_date, end_date) ).values( 'origin_id', 'origin__name', 'destination_id', 'destination__name' ).annotate( trip_count=Count('id') )
场景2:往返行程视为同一组(A→B和B→A算同一条路线)
如果需要把往返路线合并统计,Django ORM直接做有点局限,我们可以先按场景1拿到统计结果,再在Python层面处理:
from collections import defaultdict # 先拿到场景1的trip_stats结果 combined_stats = defaultdict(int) for stat in trip_stats: # 生成排序后的键,让('A','B')和('B','A')变成同一个键 route_key = tuple(sorted((stat['origin__name'], stat['destination__name']))) combined_stats[route_key] += stat['trip_count'] # 转换成更易读的格式 final_stats = [ {'route': f"{k[0]} ↔ {k[1]}", 'total_trips': v} for k, v in combined_stats.items() ]
注意事项
- 确保你的Trip模型里有日期字段(不管是
DateField还是DateTimeField,__range筛选器都能生效); - 如果你的起点/终点允许为空,空值也会被当成一个独立的分组,要是想排除空值,在
filter()里加origin__isnull=False, destination__isnull=False即可。
内容的提问来源于stack exchange,提问作者Josh21
相关产品推荐
相关产品推荐

