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

Django ORM按天统计记录时缺失日期自动补0的实现方法

这个需求两种实现方式都可行,你可以根据项目场景选择对应方案:

方案1:纯Python实现(无额外依赖,全数据库兼容)

适合数据量不大的场景,不需要引入pandas,也不需要写原生SQL,兼容性最好。

from datetime import timedelta, datetime
from django.db.models import Count
from django.db.models.functions import TruncDate

# 先将起止字符串转为date类型,保证后续键匹配类型一致
start_date = datetime.strptime('2021-9-1', '%Y-%m-%d').date()
end_date = datetime.strptime('2021-9-30', '%Y-%m-%d').date()

# 原有ORM查询,拿到有数据的日期统计结果
date_counts = Tracking.objects.filter(
    scan_time__date__gte=start_date,
    scan_time__date__lte=end_date
).annotate(
    scanned_date=TruncDate('scan_time')
).values('scanned_date').annotate(
    total=Count('created')
).order_by('scanned_date')

# 转为日期为键、统计数为值的字典,提高查询效率
count_map = {item['scanned_date']: item['total'] for item in date_counts}

# 生成全量日期序列,遍历补0
full_result = []
current_date = start_date
while current_date <= end_date:
    full_result.append({
        'scanned_date': current_date,
        'total': count_map.get(current_date, 0)
    })
    current_date += timedelta(days=1)

遍历full_result即可输出你需要的日期: 统计数格式内容。

方案2:Django ORM + 原生SQL实现(适合大数据量场景)

如果数据量很大,不想在Python层做循环,可以结合数据库的连续序列生成能力直接查询,以PostgreSQL为例:

from django.db import connection

sql = """
    SELECT series.date::date AS scanned_date, COALESCE(t.total, 0) AS total
    FROM generate_series(%s::date, %s::date, '1 day'::interval) AS series(date)
    LEFT JOIN (
        SELECT DATE(scan_time) AS scan_date, COUNT(created) AS total
        FROM tracking
        WHERE DATE(scan_time) BETWEEN %s AND %s
        GROUP BY DATE(scan_time)
    ) t ON t.scan_date = series.date
    ORDER BY series.date
"""

with connection.cursor() as cursor:
    cursor.execute(sql, [start_date, end_date, start_date, end_date])
    query_result = cursor.fetchall()

# 转为字典格式
full_result = [{'scanned_date': item[0], 'total': item[1]} for item in query_result]

MySQL 8.0+ 也可以用递归CTE生成连续日期,替换对应SQL即可。

方案3:Pandas实现(适合需要后续数据分析的场景)

如果项目已经引入Pandas做报表分析,几行代码即可完成补0操作:

import pandas as pd

# 把原有ORM查询结果转为DataFrame
count_df = pd.DataFrame(date_counts)
count_df['scanned_date'] = pd.to_datetime(count_df['scanned_date']).dt.date

# 生成全量日期序列,重建索引补0
full_dates = pd.date_range(start=start_date, end=end_date, freq='D').date
full_df = count_df.set_index('scanned_date').reindex(full_dates, fill_value=0).reset_index()
full_df.rename(columns={'index': 'scanned_date'}, inplace=True)

# 转为字典列表格式
full_result = full_df.to_dict('records')

内容的提问来源于stack exchange,提问作者Anuj TBE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 10:45:10