Django(18)聚合函式

Silent丿丶黑羽發表於2021-05-19

前言

orm模型中的聚合函式跟MySQL中的聚合函式作用是一致的,也有像SumAvgCountMaxMin,接下來我們逐個介紹
 

聚合函式

所有的聚合函式都是放在django.db.models下面。並且聚合函式不能夠單獨的執行,聚合函式是通過aggregate方法來實現的。在說明聚合函式的用法的時候,都是基於以下的模型物件來實現的。

class Author(models.Model):
     """作者模型"""
     name = models.CharField(max_length=100)
     age = models.IntegerField()
     email = models.EmailField()

     class Meta:
         db_table = 'author'


 class Publisher(models.Model):
     """出版社模型"""
     name = models.CharField(max_length=300)

     class Meta:
         db_table = 'publisher'


 class Book(models.Model):
     """圖書模型"""
     name = models.CharField(max_length=300)
     pages = models.IntegerField()
     price = models.FloatField()
     rating = models.FloatField()
     author = models.ForeignKey(Author,on_delete=models.CASCADE)
     publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)

     class Meta:
         db_table = 'book'


 class BookOrder(models.Model):
     """圖書訂單模型"""
     book = models.ForeignKey("Book",on_delete=models.CASCADE)
     price = models.FloatField()

     class Meta:
         db_table = 'book_order'

 

Avg

Avg:求平均值。比如想要獲取所有圖書的價格平均值。那麼可以使用以下程式碼實現。

 from django.db.models import Avg
 result = Book.objects.aggregate(Avg('price'))
 print(result)

 
以上的列印結果是:

 {"price__avg":23.0}

其中price__avg的結構是根據field__avg規則構成的。如果想要修改預設的名字,那麼可以將Avg賦值給一個關鍵字引數。示例程式碼如下:

 from django.db.models import Avg
 result = Book.objects.aggregate(my_avg=Avg('price'))
 print(result)

以上的列印結果為

 {"my_avg":23}

 

Count

Count:獲取指定的物件的個數。示例程式碼如下:

 from django.db.models import Count
 result = Book.objects.aggregate(book_num=Count('id'))

以上的result將返回Book表中總共有多少本圖書。
Count類中,還有另外一個引數叫做distinct,預設是等於False,如果是等於True,那麼將去掉那些重複的值。比如要獲取作者表中所有的不重複的郵箱總共有多少個,那麼可以通過以下程式碼來實現:

from djang.db.models import Count
result = Author.objects.aggregate(count=Count('email',distinct=True))

 

Max和Min

Max和Min:獲取指定物件的最大值和最小值。比如想要獲取Author表中,最大的年齡和最小的年齡分別是多少。那麼可以通過以下程式碼來實現:

from django.db.models import Max,Min
result = Author.objects.aggregate(Max('age'),Min('age'))

如果最大的年齡是90,最小的年齡是10。那麼以上的result將為:

{"age__max":90,"age__min":10}

 

Sum

Sum:求指定物件的總和。比如要求圖書的銷售總額。那麼可以使用以下程式碼實現:

from djang.db.models import Sum
result = Book.objects.annotate(total=Sum("bookorder__price"))

以上的程式碼annotate的意思是給Book表在查詢的時候新增一個欄位叫做total,這個欄位的資料來源是從BookOrder模型的price的總和而來。
 

aggregate和annotate的區別

  • 相同點:這兩個方法都可以執行聚合函式。
  • 不同點:
    • aggregate返回的是一個字典,在這個字典中儲存的是這個聚合函式執行的結果。而annotate返回的是一個QuerySet物件,並且會在查詢的模型上新增一個聚合函式的屬性。
    • aggregate不會做分組,而annotate會使用group by子句進行分組,只有呼叫了group by子句,才能對每一條資料求聚合函式的值。

 

F表示式:

F表示式: 動態的獲取某個欄位上的值。並且這個F表示式,不會真正的去資料庫中查詢資料,他相當於只是起一個標識的作用。比如想要將原來每本圖書的價格都在原來的基礎之上增加10元,那麼可以使用以下程式碼來實現:

from django.db.models import F
Book.objects.update(price=F("price")+10)

 

Q表示式

Q表示式:使用Q表示式包裹查詢條件,可以在條件之間進行多種操作。與/或非等,從而實現一些複雜的查詢操作。例子如下:

  • 查詢價格大於100,並且評分達到4.85以上的圖書:
  # 不使用Q表示式的
  books = Book.objects.filter(price__gte=100,rating__gte=4.85)
  # 使用Q表示式的
  books = Book.objects.filter(Q(price__gte=100)&Q(rating__gte=4.85))
  • 查詢價格低於100元,或者評分低於4分的圖書:
books = Book.objects.filter(Q(price__gte=100)&Q(rating__gte=4.85))
  • 獲取價格大於100,並且圖書名字中不包含”傳“字的圖書:
books = Book.objects.filter(Q(price__gte=100)&~Q(name__icontains='傳'))

相關文章