Django ORM 为缺失日期填充 0

Django ORM fill 0 for missing date

我正在使用 Django 2.2

我想生成展期和结束日期之间每一天的记录数分析。 使用的查询是

start_date = '2021-9-1'
end_date = '2021-9-30'

query = Tracking.objects.filter(
  scan_time__date__gte=start_date,
  scan_time__date__lte=end_date
)

query.annotate(
  scanned_date=TruncDate('scan_time')
).order_by(
  'scanned_date'
).values('scanned_date').annotate(
  **{'total': Count('created')}
)

产生的输出为

[{'scanned_date': datetime.date(2021, 9, 24), 'total': 5}, {'scanned_date': datetime.date(2021, 9, 26), 'total': 3}]

我想用 0 填充缺失的日期,这样输出应该是

2021-9-1: 0
2021-9-2: 0
...
2021-9-24: 5
2021-9-25: 0
2021-9-26: 3
...
2021-9-30: 0

如何使用 ORM 或 python(即 pandas 等)实现此目的?

使用DataFrame.reindex by date range created by date_range with DatetimeIndex by DataFrame.set_index:

data = [{'scanned_date': datetime.date(2021, 9, 24), 'total': 5},
        {'scanned_date': datetime.date(2021, 9, 26), 'total': 3}]

start_date = '2021-9-1'
end_date = '2021-9-30'

r = pd.date_range(start_date, end_date, name='scanned_date')
#if necessary convert to dates from datetimes
#r = pd.date_range(start_date, end_date, name='scanned_date').date
df = pd.DataFrame(data).set_index('scanned_date').reindex(r, fill_value=0).reset_index()

print (df)
   scanned_date  total
0    2021-09-01      0
1    2021-09-02      0
2    2021-09-03      0
3    2021-09-04      0
4    2021-09-05      0
5    2021-09-06      0
6    2021-09-07      0
7    2021-09-08      0
8    2021-09-09      0
9    2021-09-10      0
10   2021-09-11      0
11   2021-09-12      0
12   2021-09-13      0
13   2021-09-14      0
14   2021-09-15      0
15   2021-09-16      0
16   2021-09-17      0
17   2021-09-18      0
18   2021-09-19      0
19   2021-09-20      0
20   2021-09-21      0
21   2021-09-22      0
22   2021-09-23      0
23   2021-09-24      5
24   2021-09-25      0
25   2021-09-26      3
26   2021-09-27      0
27   2021-09-28      0
28   2021-09-29      0
29   2021-09-30      0

或者使用另一个 DataFrame 的左连接从范围创建,并将错误值替换为 0:

r = pd.date_range(start_date, end_date, name='scanned_date').date

df = pd.DataFrame({'scanned_date':r}).merge(pd.DataFrame(data), how='left', on='scanned_date').fillna(0)