Django 1.10中文文件-聚合
正文
Django 資料庫抽象API 描述了使用Django 查詢來增刪查改單個物件的方法。 然而,有時候你要獲取的值需要根據一組物件聚合後才能得到。 這個主題指南描述瞭如何使用Django的查詢來生成和返回聚合值的方法。
整篇指南我們都將引用以下模型。這些模型用來記錄多個網上書店的庫存。
from django.db import models class Author(models.Model): name = models.CharField(max_length=100) age = models.IntegerField() class Publisher(models回到頂部.Model): name = models.CharField(max_length=300) num_awards = models.IntegerField() class Book(models.Model): name = models.CharField(max_length=300) pages = models.IntegerField() price = models.DecimalField(max_digits=10, decimal_places=2) rating = models.FloatField() authors= models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) pubdate = models.DateField() class Store(models.Model): name = models.CharField(max_length=300) books = models.ManyToManyField(Book) registered_users = models.PositiveIntegerField()
速查表
下面是在上面的模型上如何執行常見的聚合查詢:
# book 總數. >>> Book.objects.count() 2452 # publisher=BaloneyPress的book總數. >>> Book.objects.filter(publisher__name='BaloneyPress').count() 73 # 所有book的平均價格. >>> from django.db.models import Avg >>> Book.objects.all().aggregate(Avg('price')) {'price__avg': 34.35} # 所有book的最高價格 >>> from django.db.models import Max >>> Book.objects.all().aggregate(Max('price')) {'price__max': Decimal('81.20')} # 每頁均價 >>> from django.db.models import F, FloatField, Sum >>> Book.objects.all().aggregate( ... price_per_page=Sum(F('price')/F('pages'), output_field=FloatField())) {'price_per_page': 0.4470664529184653} # 下面的所有查詢都涉及到遍歷 Book<->Publisher # foreign key relationship backwards. # Each publisher, each with a count of books as a "num_books" attribute. >>> from django.db.models import Count >>> pubs = Publisher.objects.annotate(num_books=Count('book')) >>> pubs <QuerySet [<Publisher: BaloneyPress>, <Publisher: SalamiPress>, ...]> >>> pubs[0].num_books 73 # The top 5 publishers, in order by number of books. >>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5] >>> pubs[0].num_books 1323回到頂部
QuerySet
聚合
Django提供了兩種生成聚合的方法。第一種方法是從整個 QuerySet
生成統計值。
比如,你想要計算所有在售書的平均價錢。Django的查詢語法提供了一種方式描述所有圖書的集合。:
>>> Book.objects.all()
我們需要在 QuerySet
物件上計算出彙總的值。這可以通過在 QuerySet
後面新增 aggregate()
子句來實現:
>>> from django.db.models import Avg >>> Book.objects.all().aggregate(Avg('price')) {'price__avg': 34.35}
其實 all()
在這裡可以省略,簡化為:
>>> Book.objects.aggregate(Avg('price')) {'price__avg': 34.35}
aggregate()
子句的引數是想要計算的聚合值,在這個例子中,是 Book
模型中 price
欄位的平均值。 查詢集參考 有所有的聚合函式。
aggregate()
是 QuerySet
的一個終止子句,意思是說,它返回一個包含鍵值對的字典。
鍵的名稱是聚合值的識別符號,值是計算出來的聚合值。鍵的名稱是按照欄位和聚合函式的名稱自動生成出來的。 如果你想要為聚合值指定一個名稱,可以在聚合子句中指定:
>>> Book.objects.aggregate(average_price=Avg('price')) {'average_price': 34.35}
如果你想要計算多個聚合,你可以在 aggregate()
子句作為引數新增。比如,
如果你也想知道所有圖書價格的最大值和最小值,可以這樣查詢:
>>> from django.db.models import Avg, Max, Min >>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) {'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}回到頂部
QuerySet
逐個物件的聚合
生成彙總值的第二種方法,是為 QuerySet
中每一個物件都生成一個獨立的彙總值。
比如,你可能想知道每一本書有多少作者參與。每本書和作者是多對多的關係。 我們需要彙總 QuerySet
中每本書的這種關係。
逐個物件的彙總結果可以由 annotate()
子句生成。
當 annotate()
子句被指定之後, QuerySet
中的每個物件都會被註上特定的值。
annotate(註解)的語法都和 aggregate()
子句相同。 annotate()
的每個引數都描述了將要被計算的聚合值。
比如,給圖書新增作者數量的註解:
# Build an annotated queryset >>> from django.db.models import Count >>> q = Book.objects.annotate(Count('authors')) # 查詢queryset中的第一個物件 >>> q[0] <Book: The Definitive Guide to Django> >>> q[0].authors__count 2 # 查詢queryset中的第二個物件 >>> q[1] <Book: Practical Django Projects> >>> q[1].authors__count 1
和 aggregate()
一樣,註解的名稱也根據聚合函式的名稱和聚合欄位的名稱自動生成。
同樣可以在指定註釋時,通過提供別名來覆蓋此預設名稱:
>>> q = Book.objects.annotate(num_authors=Count('authors')) >>> q[0].num_authors 2 >>> q[1].num_authors