Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django count grouping by year/month without extra

I'm working with django 1.9

Model :

class Comment(models.Model):
    title = models.CharField(max_length=250, null=False)
    date = models.DateField(auto_now_add=True)

As 'extra()' will be deprecated in django i try to figure out how to count Comments group by year-month without using 'extra'

Here is the code with extra :

Comment.objects.extra(select={'year': "EXTRACT(year FROM date)",
    'month': "EXTRACT(month from date)"})\
    .values('year', 'month').annotate(Count('pk'))

Thank you for your help.

like image 418
Ange Concerto Avatar asked Feb 12 '16 17:02

Ange Concerto


1 Answers

See year and month in the docs, may be something like the following will do the job:

Comment.objects.annotate(year=Q(date__year), 
                         month=Q(date__month)
                         ).values('year', 'month').annotate(Count('pk'))

If this won't work, then instead of Q(date__year), you could define a custom Func() expression representing EXTRACT(year FROM date) function and use it in annotate(). Or, well, as last resort there's RawSQL().

Using Func(), something like this:

from django.db.models import Func

class Extract(Func):
    """
    Performs extraction of `what_to_extract` from `*expressions`.

    Arguments:
        *expressions (string): Only single value is supported, should be field name to
                               extract from.
        what_to_extract (string): Extraction specificator.

    Returns:
        class: Func() expression class, representing 'EXTRACT(`what_to_extract` FROM `*expressions`)'.
    """

    function = 'EXTRACT'
    template = '%(function)s(%(what_to_extract)s FROM %(expressions)s)'


#Usage
Comment.objects.annotate(year=Extract(date, what_to_extract='year'), 
                             month=Extract(date, what_to_extract='month')
                             ).values('year', 'month').annotate(Count('pk'))
like image 137
Nikita Avatar answered Sep 23 '22 21:09

Nikita