2010-08-22 5 views
15

J'ai un modèle très basique:Django annoter groupes par mois

class Link(models.Model): 
    title = models.CharField(max_length=250, null=False) 
    user = models.ForeignKey(User) 
    url = models.CharField(max_length=250, blank=True, null=True) 
    link_count = models.IntegerField(default=0) 
    pub_date = models.DateField(auto_now_add=True) 
    updated = models.DateTimeField(auto_now=True) 

Je peux créer une liste de toutes les entrées groupées par jour à l'aide:

Link.objects.values('pub_date').order_by('-pub_date').annotate(dcount=Count('pub_date')) 

Ce sera naturellement regrouper les éléments par jour . Mais ce que je veux vraiment faire, c'est le groupe par mois. Y at-il de toute façon que je peux le faire en utilisant annotate()?

Un grand merci,

G

+0

Pas une réponse, mais vous pourriez prendre regarde ce billet: http://code.djangoproject.com/ticket/10302 –

+0

ce qui est 'Count'? –

Répondre

15

Si vous êtes sur PostgreSQL, ce qui suit pourrait fonctionner:

from django.db.models import Count 

Link.objects.extra(select={'month': 'extract(month from pub_date)'}).values('month').annotate(dcount=Count('pub_date')) 

Je ne sais pas comment extract portable est dans d'autres bases de données.

+0

Merci! Cela semble fonctionner aussi pour mySQL. Sauf que ces groupes tous les mois à travers une année. J'essaie d'obtenir des mois groupés pour chaque année. Mais c'est un bon début, donc je vais modifier. Merci encore. – givp

+0

vous pouvez claquer un filtre qui limite les dates à certaines plages. '.filter (pub_date__gte = datetime.datetime (date de remplissage ici))' – boatcoder

+4

en utilisant 'connection.ops.date_trunc_sql ('month', 'date')' au lieu de l'extrait en dur extrait SQL rendrait la déclaration compatible avec les autres backends – jujule

13
from django.db import connections 
from django.db.models import Count 

Link.objects.extra(select={'month': connections[Link.objects.db].ops.date_trunc_sql('month', 'pub_date')}).values('month').annotate(dcount=Count('pub_date')) 
+1

Note que vous devez également importer 'from from django.db.models import Count' –

3

Pour ajouter, comme une alternative à l'utilisation extra(): depuis Django 1.8, vous pouvez également utiliser des expressions conditionnelles.

>>> year_overview = Link.objects.filter(pub_date__year=year).aggregate(
    jan=Sum(
     Case(When(created__month=0, then=1), 
      output_field=IntegerField()) 
    ), 
    feb=Sum(
     Case(When(created__month=1, then=1), 
      output_field=IntegerField()) 
    ), 
    mar=Sum(
     Case(When(created__month=2, then=1), 
      output_field=IntegerField()) 
    ), 
    apr=Sum(
     Case(When(created__month=3, then=1), 
      output_field=IntegerField()) 
    ), 
    may=Sum(
     Case(When(created__month=4, then=1), 
      output_field=IntegerField()) 
    ), 
    jun=Sum(
     Case(When(created__month=5, then=1), 
      output_field=IntegerField()) 
    ), 
    jul=Sum(
     Case(When(created__month=6, then=1), 
      output_field=IntegerField()) 
    ), 
    aug=Sum(
     Case(When(created__month=7, then=1), 
      output_field=IntegerField()) 
    ), 
    sep=Sum(
     Case(When(created__month=8, then=1), 
      output_field=IntegerField()) 
    ), 
    oct=Sum(
     Case(When(created__month=9, then=1), 
      output_field=IntegerField()) 
    ), 
    nov=Sum(
     Case(When(created__month=10, then=1), 
      output_field=IntegerField()) 
    ), 
    dec=Sum(
     Case(When(created__month=11, then=1), 
      output_field=IntegerField()) 
    ), 
) 

>>> year_overview 
{'mar': None, 'feb': None, 'aug': None, 'sep': 95, 'apr': 1, 'jun': None, 'jul': None, 'jan': None, 'may': None, 'nov': 87, 'dec': 94, 'oct': 100} 
+2

Avec la dernière version de Django, je suppose que c'est la solution recommandée –

2

J'ai lu que .extra() sera obsolète dans le futur. Ils suggèrent d'utiliser plutôt des objets Func. Et il y en a un pour extraire un mois sans utiliser une instruction Case douloureuse.

from django.db.models.functions import ExtractMonth 
Link.objects.all().annotate(pub_date_month=ExtractMonth('pub_date'))