Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django, how to group models by date?

Tags:

python

django

Lets say that I have MyModel that has created_at and name fields. created_at is DateTime.

Lets say that I have the following model objects:

<id: 1, name: A, created_at: 04.06.2020T17:49>
<id: 2, name: B, created_at: 04.06.2020T18:49>
<id: 3, name: C, created_at: 05.06.2020T20:00>
<id: 4, name: D, created_at: 06.06.2020T19:20>
<id: 5, name: E, created_at: 06.06.2020T13:29>
<id: 6, name: F, created_at: 06.06.2020T12:55>

I want to make query that will return to me these models in this order:

[
    04.06.2020: [<id: 1, name: A, created_at: 04.06.2020T17:49>, <id: 2, name: B, created_at: 04.06.2020T18:49>],
    05.06.2020: [<id: 3, name: C, created_at: 05.06.2020T20:00>]
    06.06.2020: [<id: 4, name: D, created_at: 06.06.2020T19:20>, <id: 5, name: E, created_at: 06.06.2020T13:29>, <id: 6, name: F, created_at: 06.06.2020T12:55>]
]

I want to group all models by created_at field, but only using Date part of DateTime field. I know that I can make that kind of result just by using python loops, but are there any Django ORM way to solve this problem?

like image 488
Mr.D Avatar asked Jun 04 '20 11:06

Mr.D


2 Answers

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:
    ...
like image 109
Simon Charette Avatar answered Sep 21 '22 08:09

Simon Charette


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.

like image 35
hardik24 Avatar answered Sep 20 '22 08:09

hardik24