Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django aggregation over choices

I have a following model:

class VotingRound(models.Model):
     pass # here are some unimportant fields

class Vote(models.Model):
     voting_round = models.ForeignKey(VotingRound)
     vote = models.CharField(choices=...)

Now I have instance of VotingRound and I would like to get to know how many times was each value represented. This is easily done through collections.Counter:

>>> Counter(voting_round_instance.vote_set.values_list('vote', flat=True))
Counter({u'decline': 8, u'neutral': 5, u'approve': 4})

Now I would like to know if there is a way to do this with Django aggregation techniques....

I have found this module, but before using it I wanted to know if there is native way to do it.

like image 451
Visgean Skeloru Avatar asked Apr 24 '15 00:04

Visgean Skeloru


1 Answers

yes, you can!

from django.db.models import Count
voting_round_instance.vote_set.values('vote') \
    .annotate(count=Count('vote')).distinct()

EDIT : use order_by()

You may also need to make sure the default ordering does not mess up your aggregation. This is especially true when using related object managers.

https://docs.djangoproject.com/en/1.8/topics/db/aggregation/#interaction-with-default-ordering-or-order-by

Fields that are mentioned in the order_by() part of a queryset (or which are used in the default ordering on a model) are used when selecting the output data, even if they are not otherwise specified in the values() call. These extra fields are used to group “like” results together and they can make otherwise identical result rows appear to be separate. This shows up, particularly, when counting things.

from django.db.models import Count
voting_round_instance.vote_set.values('vote') \
    .annotate(count=Count('vote')) \
    .distinct().order_by()
like image 116
dnozay Avatar answered Oct 23 '22 12:10

dnozay