Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
253 views
in Technique[技术] by (71.8m points)

python - How to execute a GROUP BY ... COUNT or SUM in Django ORM?

Prologue:

This is a question arising often in SO:

I have composed an example on SO Documentation but since the Documentation will get shut down on August 8, 2017, I will follow the suggestion of this widely upvoted and discussed meta answer and transform my example to a self-answered post.

Of course, I would be more than happy to see any different approach as well!!


Question:

Assume the model:

class Books(models.Model):
    title  = models.CharField()
    author = models.CharField()
    price = models.FloatField()

How can I perform the following queries on that model utilizing Django ORM:

  • GROUP BY ... COUNT:

    SELECT author, COUNT(author) AS count
    FROM myapp_books GROUP BY author
    
  • GROUP BY ... SUM:

    SELECT author,  SUM (price) AS total_price
    FROM myapp_books GROUP BY author
    
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

We can perform a GROUP BY ... COUNT or a GROUP BY ... SUM SQL equivalent queries on Django ORM, with the use of annotate(), values(), the django.db.models's Count and Sum methods respectfully and optionally the order_by() method:

  • GROUP BY ... COUNT:

     from django.db.models import Count
    
     result = Books.objects.values('author')
                           .order_by('author')
                           .annotate(count=Count('author'))
    

    Now result contains a dictionary with two keys: author and count:

       author    | count
     ------------|-------
      OneAuthor  |   5
     OtherAuthor |   2
        ...      |  ...
    
  • GROUP BY ... SUM:

     from django.db.models import Sum
    
      result = Books.objects.values('author')
                            .order_by('author')
                            .annotate(total_price=Sum('price'))
    

    Now result contains a dictionary with two columns: author and total_price:

       author    | total_price
     ------------|-------------
      OneAuthor  |    100.35
     OtherAuthor |     50.00
         ...     |      ...
    

UPDATE 13/04/2021

As @dgw points out in the comments, in the case that the model uses a meta option to order rows (ex. ordering), the order_by() clause is paramount for the success of the aggregation!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...