Django - Group By только с датой

MyModel.objects.filter(created_at__gte='2011-03-09', created_at__lte='2011-03-11').values('created_at','status').annotate(status_count=Count('status'))

Приведенный выше запрос имеет проблему с полем даты и времени created_at. Можно ли настроить приведенный выше запрос, чтобы он игнорировал значение времени и использовал только значение даты при выполнении группы?


person Sivasubramaniam Arunachalam    schedule 10.03.2011    source источник


Ответы (4)


Я не уверен, может ли Django ORM выполнять преобразование даты и времени в даты в середине запроса. Однако вы можете сначала выполнить запрос, получить результаты, а затем использовать функцию Python groupby() для сортировки возвращаемых строк. Вот небольшой пример группировки даты и времени по дате:

from pprint import pprint
from datetime import datetime
from itertools import groupby

rows = [('Frodo party', datetime(3018, 9, 22, 10, 38)),
        ('Nazgul defeat Rangers', datetime(3018, 9, 22, 11, 57)),
        ('Frodo finishes packing', datetime(3018, 9, 23, 10, 59)),
        ('Gandalf tames Shadowfax', datetime(3018, 9, 23, 13, 11)),
        ('Gandalf crosses the Isen', datetime(3018, 9, 24, 18, 46))]

for key, values in groupby(rows, key=lambda row: row[1].date()):
    print('-')
    pprint(key)
    pprint(list(values))

Как видите, вы должны предоставить groupby() функцию key, которая берет один из объектов, которые она группирует, и извлекает значение, по которому должна происходить группировка — в этом случае она захватывает второй элемент в каждой строке с помощью [1]. а затем вызывает метод Python datetime date() для извлечения части даты без часов и минут. Вывод скрипта выглядит следующим образом (функция pprint() — это просто причудливый оператор «print», который делает отступ в выводе, он не понадобится в вашем коде Django!):

-
datetime.date(3018, 9, 22)
[('Frodo party', datetime.datetime(3018, 9, 22, 10, 38)),
 ('Nazgul defeat Rangers', datetime.datetime(3018, 9, 22, 11, 57))]
-
datetime.date(3018, 9, 23)
[('Frodo finishes packing', datetime.datetime(3018, 9, 23, 10, 59)),
 ('Gandalf tames Shadowfax', datetime.datetime(3018, 9, 23, 13, 11))]
-
datetime.date(3018, 9, 24)
[('Gandalf crosses the Isen', datetime.datetime(3018, 9, 24, 18, 46))]
person Brandon Rhodes    schedule 10.03.2011

Я слишком поздно для этого вопроса, но для дальнейшего использования я хочу указать, что это действительно возможно с собственным Django, как описано в https://stackoverflow.com/a/2283913

person bradenm    schedule 07.05.2012
comment
метод .extra() фактически добавляет вызовы уровня БД, поэтому технически это не «родной Django». - person avramov; 24.02.2013

Да, это возможно с использованием «дополнительных» функций форматирования даты на уровне БД. Реализация может быть найдена, например, в Пакет django-qsstats-magic.

person Mikhail Korobov    schedule 10.03.2011

Вы можете сделать это легко, используя дополнительное ключевое слово в django.

MyModel.objects
.filter(created_at__gte='2011-03-09', created_at__lte='2011-03-11')
.extra({"created_at":"date_trunc('day', created_at)"}).values('created_at','status').annotate(status_count=Count('status'))

date_trunc - это функция postgres, которую она принимает, указана только точность.

person Heisenberg    schedule 11.07.2017