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

如何使用Django QuerySet查询DateRange模型连续相同值的日期区间

Django QuerySet 实现连续相同值分组查询方案

假设你的模型中存储示例里1、2的字段名为value,date字段为Django原生DateField类型。


方案1:数据库端窗口函数实现(推荐,适配大数据量场景)

这是经典的「缝隙与岛屿」SQL问题,可直接通过Django ORM调用窗口函数在数据库端完成计算,性能远高于内存处理:

from django.db.models import Window, F, Lag, Sum, Case, When, IntegerField, Min, Max

# 标记分组边界并生成分组ID
queryset = DateRange.objects.annotate(
    # 按日期升序排序,取上一行的value值
    prev_value=Window(
        expression=Lag('value'),
        order_by=F('date').asc()
    )
).annotate(
    # 当前行和上一行value不同/是第一行时,标记为新分组的起点
    group_start=Case(
        When(prev_value__isnull=True, then=1),
        When(prev_value=F('value'), then=0),
        default=1,
        output_field=IntegerField()
    )
).annotate(
    # 累加分组起点标记,得到每个连续组的唯一分组ID
    group_id=Window(
        expression=Sum('group_start'),
        order_by=F('date').asc()
    )
)

# 按分组ID和value聚合,取每个组的起止日期
result = queryset.values('group_id', 'value').annotate(
    start_date=Min('date'),
    end_date=Max('date')
).order_by('group_id')

方案2:Python内存处理(适配小数据量/低版本不支持窗口函数的数据库)

如果数据量小于10万条,或者使用的是不支持窗口函数的低版本数据库,可以直接在内存中处理:

# 按日期升序取出所有数据
all_data = DateRange.objects.order_by('date').values('date', 'value')
result = []

if all_data:
    # 初始化第一个分组
    current_group = {
        "value": all_data[0]["value"],
        "start_date": all_data[0]["date"],
        "end_date": all_data[0]["date"]
    }
    for item in all_data[1:]:
        if item["value"] == current_group["value"]:
            # 同一分组,更新结束日期
            current_group["end_date"] = item["date"]
        else:
            # 新分组,保存旧分组并初始化新分组
            result.append(current_group)
            current_group = {
                "value": item["value"],
                "start_date": item["date"],
                "end_date": item["date"]
            }
    # 保存最后一个分组
    result.append(current_group)

输出效果

遍历得到的result即可打印你需要的格式:

for item in result:
    print(f"{item['value']} 存在于 {item['start_date'].strftime('%d-%m-%Y')} - {item['end_date'].strftime('%d-%m-%Y')}")

注意事项

  • 必须保证date字段为日期类型,若存储为字符串需先转换为日期格式,否则排序会出错
  • 窗口函数方案仅支持MySQL 8.0+、PostgreSQL、SQLite 3.25+及以上支持窗口函数的数据库版本

内容的提问来源于stack exchange,提问作者raj-kapil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 21:36:00