Django 按日期注释数据以获取空结果

问题描述 投票:0回答:2

假设我有一个对象模型A,它有一个名为created的字段,这是一个日期时间类型的字段。

如果我使用annotate来统计每天创建了多少个A,我可以使用

A.objects.annotate(date=Trunc('created', 'day', output_field=DateField()) ).values('date').order_by('date').annotate(count=Count('id'))

之后我就可以得到结果了,看起来像这样

[{date: '2018-07-22', count:1 }, {date: '2018-07-23', count:1 }, {date: '2018-07-25', count:1 }]

但是,请注意,我错过了 2018-07-24,因为它在那一天没有创建任何 A。有没有办法让结果在查询集中有

{date: '2018-07-24', count:0 }

python django orm django-annotate
2个回答
0
投票

我的 PostgreSQL 变体:

from datetime import date, timedelta
from django.db.models.functions import Trunc
from django.db.models.expressions import Value
from django.db.models import Count, DateField

# A is model

start_date = date(2022, 5, 1)
end_date = date(2022, 5, 10)

result = A.objects\
    .annotate(date=Trunc('created', 'day', output_field=DateField())) \
    .filter(date__gte=start_date, date__lte=end_date) \
    .values('date')\
    .annotate(count=Count('id'))\
    .union(A.objects.extra(select={
             'date': 'unnest(Array[%s]::date[])' %
                     ','.join(map(lambda d: "'%s'::date" % d.strftime('%Y-%m-%d'),
                                  set(start_date + timedelta(n) for n in range((end_date - start_date).days + 1)) -
                                  set(A.objects.annotate(date=Trunc('created', 'day', output_field=DateField())) \
                                               .values_list('date', flat=True))))})\
            .annotate(count=Value(0))\
            .values('date', 'count'))\
    .order_by('date')

0
投票

你可以试试这个:

定义您的日期范围

start_date = datetime(2018, 7, 22).date()
end_date = datetime(2018, 7, 25).date()

注释查询集以计算每个日期的出现次数

annotated_queryset = A.objects.annotate(
    date=TruncDate('created')
).values('date').annotate(
    count=Count('id')
).order_by('date')

生成日期范围内的日期列表

date_objects = [start_date + timedelta(days=i) for i in range((end_date - start_date).days + 1)]

创建一个字典,将日期映射到带注释的查询集中的计数

count_dict = {entry['date']: entry['count'] for entry in annotated_queryset}

创建包含范围内所有日期及其各自计数的字典列表, 填写缺失日期且计数为零

result = [
    {'date': date.strftime('%Y-%m-%d'), 'count': count_dict.get(date, 0)}
    for date in date_objects
]
© www.soinside.com 2019 - 2024. All rights reserved.