varad
varad

Reputation: 8039

django order by count of many to many object

I have a model :

class Category(models.Model):
    questions = models.ManyToManyField('Question', related_name="cat_question", blank=True)
    cat_name = models.CharField(max_length=50)
    cat_description = models.CharField(max_length=255)

    def __unicode__(self):
        return self.cat_name

and in my view I have :

top_categories = Category.objects.all()[:7].

I am passing it as context in the template. I want to sort the top categories by the number of questions in it like if A category has most question then it should be in top and if B has most question then B. Then second most and so on..

like top_categories = Category.objects.all().order_by(Count(question)

Any help ?

Upvotes: 7

Views: 5168

Answers (2)

Suh Fangmbeng
Suh Fangmbeng

Reputation: 583

In this case, they both do the same thing to sort the categories in the order of the number of questions they have in that field.

However, you will realize so many other uses .annotate() method. For example, you may want to sort the categories by the number of questions with a below and in descending order of the date.

You easily achieve this like so:

below_50 = Count('questions', filter=Q(marks__gte=50))
top_categories = Category.objects.annotate(below_50=below_50).order_by('-date')

In your situation, it's okay to just use order_by alone, but a more complex query of summing number of questions may require .annotate()

Upvotes: 0

catavaran
catavaran

Reputation: 45595

Annotate Category objects with the number of questions and then order by this number in descend order:

from django.db.models import Count

top_categories = Category.objects.annotate(q_count=Count('questions')) \
                                 .order_by('-q_count')[:7]

and you can look on the example in the doc order-by, more examples for aggreagate cheat-sheet

Upvotes: 27

Related Questions