Аннотировать (групповые) даты по месяцам / годам в Django

использование Django DateQuerySet Я тяну связанные годы для item объекты Group запрос.

>>> Group.objects.all().dates('item__date', 'year')
[datetime.date(1990, 1, 1), datetime.date(1991, 1, 1), ...(remaining elements truncated)...']

теперь я хочу выполнить подсчет по отдельным годам в эти даты. Я думал, что это сработает:

>>> Group.objects.all().dates('item__date', 'year').annotate(Count('year'))
FieldError: Cannot resolve keyword 'year' into field.

но, похоже, я что-то упускаю. Как я могу исправить этот запрос?

Я также пробовал этот запрос:

>>> (Group
     .objects
     .all()
     .extra(select=
         {'year': 
          connections[Group.objects.db].ops.date_trunc_sql('year', 'app_item.date')}))
ProgrammingError: missing FROM-clause entry for table "app_item" LINE 1: SELECT (DATE_TRUNC('year', app_item.date)) AS...

но это тоже не работает.

2 ответов


попробуйте что-нибудь в этом роде:

from django.db.models import Count

Item.objects.all().\
        extra(select={'year': "EXTRACT(year FROM date)"}).\
        values('year').\
        annotate(count_items=Count('date'))

вы можете использовать item_instance._meta.fields вместо того, чтобы вручную указывать "дату"в инструкции MySQL...

кроме того, обратите внимание, что я начал с Item QuerySet вместо Group, для простоты. Должно быть возможно либо фильтровать Item объект QuerySet, чтобы получить желаемый результат, или сделать extra бит MySQL более сложный.

EDIT:

это может работа, но я бы определенно проверил кишки из него, прежде чем полагаться на него:)

Group.objects.all().\
    values('item__date').\
    extra(select={'year': "EXTRACT(year FROM date)"}).\
    values('year').\
    annotate(count=Count('item__date'))

для тех, кто находит это после django 1.9, теперь есть TruncDate (TruncMonth, TruncYear), который сделает это.

from django.db.models.functions import TruncDate

(Group.objects.all().annotate(date=TruncDate('your_date_attr')
                    .values('date')
                    .annotate(Count('items'))

надеюсь, что это помогает.