Django TruncHour + аннотация Count not inlcuding hours with zero rows

У меня есть модель EventData

class EventData(models.Model):
    id = models.BigAutoField(primary_key=True)
    created = models.DateTimeField()
    session = models.ForeignKey(EventSession, on_delete=models.CASCADE)
    name = models.ForeignKey(EventName, on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    value = models.CharField(max_length=200)

и запрос

event_volume = IngestModels.EventData.objects.filter(product=my_product, created__date=selected_date)
  .annotate(hour=TruncHour('created'))
  .annotate(event_count=Count('*'))
  .values("hour", "event_count")

что дает результаты типа

hour event_count
2021-11-12 00:00:00 2
2021-11-12 01:00:00 2
2021-11-12 02:00:00 7
2021-11-12 05:00:00 5
2021-11-12 06:00:00 9
2021-11-12 09:00:00 10
2021-11-12 10:00:00 1
2021-11-12 12:00:00 9

Вы заметите, что есть моменты, когда никаких событий не происходило, поэтому час в строке пропущен. Мне бы очень хотелось, чтобы каждый час присутствовал и 0 в столбце event_count, если никаких событий не произошло. Таким образом, что-то вроде:

час event_count
2021-11-12 00:00:00 2
2021-11-12 01:00:00 2
2021-11-12 02:00:00 7
2021-11-12 03:00:00 0
2021-11-12 04:00:00 0
2021-11-12 05:00:00 5
2021-11-12 06:00:00 9
2021-11-12 07:00:00 0
2021-11-12 08:00:00 0
2021-11-12 09:00:00 10
2021-11-12 10:00:00 1
2021-11-12 11:00:00 0
2021-11-12 12:00:00 9

Любая помощь будет очень признательна! В качестве базы данных я использую PostgreSQL.

Я не смог решить эту проблему с помощью ORM, но это было тривиально для заполнения данных в обычном коде Python.

def time_series_pad_zeros(time_series):
    result = []
    for i in range(0,24):
        found = False
        for data in time_series:
            if data['hour'].hour == i:
                found = True
                result.append({ "hour": i, "event_count": data['event_count'] })

        if not found:
            result.append({ "hour": i, "event_count": 0 })

    return result
Вернуться на верх