web-dev-qa-db-fra.com

django moyen le plus efficace de compter les mêmes valeurs de champ dans une requête

Disons que si j'ai un modèle qui a beaucoup de champs, mais je ne me soucie que d'un champ de char. Disons que charfield peut être n'importe quoi, donc je ne connais pas les valeurs possibles, mais je sais que les valeurs se chevauchent souvent. Donc, je pourrais avoir 20 objets avec "abc" et 10 objets avec "xyz" ou je pourrais avoir 50 objets avec "def" et 80 avec "stu" et j'en ai 40000 sans chevauchement, ce qui ne m'importe vraiment pas.

Comment compter efficacement les objets? Ce que je voudrais retourner est quelque chose comme:

{'abc': 20, 'xyz': 10, 'autre': 10 000}

ou quelque chose comme ça, sans faire une tonne d'appels SQL.

ÉDITER:

Je ne sais pas si quelqu'un le verra puisque je le modifie un peu tard, mais ...

J'ai ce modèle:

 Action collective (models.Model): 
 author = models.CharField (max_length = 255) 
 purl = models.CharField (max_length = 255, null = True) 

et à partir des réponses, je l'ai fait:

 groups = Action.objects.filter (author = 'James'). values ​​('purl'). annotate (count = Count ('purl')) 

mais...

voici ce que sont les groupes:

 {"purl": "waka"}, {"purl": "waka"}, {"purl": "waka"}, {"purl": "waka"}, {"purl": "mora"}, {"purl": "mora"}, {"purl": "mora"}, {"purl": "mora"}, {"purl": "mora"}, {"purl": "lora"} 

(Je viens de remplir purl avec des valeurs fictives)

ce que je veux c'est

 {'waka': 4, 'mora': 5, 'lora': 1} 

J'espère que quelqu'un verra cette modification ...

EDIT 2:

Apparemment ma base de données (BigTable) ne prend pas en charge les fonctions d'agrégation de Django et c'est pourquoi j'ai eu tous les problèmes.

48
DantheMan

Vous voulez quelque chose de similaire à "compter ... grouper par". Vous pouvez le faire avec les fonctionnalités d'agrégation de l'ORM de Django:

from Django.db.models import Count

fieldname = 'myCharField'
MyModel.objects.values(fieldname)
    .order_by(fieldname)
    .annotate(the_count=Count(fieldname))

Questions précédentes à ce sujet:

77
beerbajay

Cela s'appelle l'agrégation et Django le supporte directement .

Vous pouvez obtenir votre sortie exacte en filtrant les valeurs que vous souhaitez compter, en obtenant la liste des valeurs et en les comptant, le tout dans un ensemble d'appels de base de données:

from Django.db.models import Count
MyModel.objects.filter(myfield__in=('abc', 'xyz')).\
        values('myfield').annotate(Count('myfield'))
16
Daniel Roseman

Vous pouvez utiliser le Countagrégation de Django sur un ensemble de requêtes pour accomplir cela. Quelque chose comme ça:

from Django.db.models import Count
queryset = MyModel.objects.all().annotate(count = Count('my_charfield'))
for each in queryset:
    print "%s: %s" % (each.my_charfield, each.count)
7
Manoj Govindan

À moins que la valeur de votre champ ne soit toujours garantie dans un cas spécifique, il peut être utile de la transformer avant d'effectuer un comptage, c'est-à-dire que 'Apple' et 'Apple' seraient traités de la même manière.

from Django.db.models import Count
from Django.db.models.functions import Lower

MyModel.objects.annotate(lower_title=Lower('title')).values('lower_title').annotate(num=Count('lower_title')).order_by('num')
1
alstr