Django, how to group models by date?

The ORM itself cannot return list of models but you can use itertools.groupby for this purpose assuming you order the dataset at the database level first.

from itertools import groupby
from operator import attrgetter

from django.db.models.functions import TruncDate

queryset = MyModel.objects.annotate(
    created_at_date=TruncDate('created_at'),
).order_by('created_at')
groupedset = groupby(queryset, attrgetter('created_at_date'))

You'll then be able able to iterate over groupedset using

for date, objects in groupedset:
    ...

You can try following code:

samples = MyModel.objects.all()
result = {}
for sample in samples:
    date_string = sample.created_at.strftime("%m.%d.%Y")
    if date_string in result:
        result[date_string].append(sample)
    else:
        result[date_string] = [sample]

It will return output like following:

{
'06.07.2020': [<Sample: MyModel object (1)>],
'05.07.2020': [<Sample: MyModel object (2)>, <Sample: MyModel object (3)>]
}

Basically, what it does it it first fetches all the rows and then group it at python level into a dictionary.


I'm afraid this is currently not completely possible, at least to my knowledge (without some really deep modifications within the Django ORM).

What you can do, however, is doing date conversions and aggregations within the database:

This example assumes your database supports the to_char function.

qs = MyModel.objects.all()
qs.annotate(
  created_at_date=models.Func(
    models.F('created_at'),
    models.Value("'dd.MM.yyyy'"),
    function='to_char',
  )
).values('created_at_date').aggregate(
    # do required aggregations like Count or Sum
)

[edit] some fixes + as bryan60 correctly pointed out, you can also use Trunc:

from django.db.models.functions import Trunc
MyModel.objects.all().annotate(
    created_at_trunc=Trunc('created_at', 'day', output_field=models.DateTimeField())
).values('created_at_trunc')

Tags:

Python

Django