1. 程式人生 > >Django之ORM-補充

Django之ORM-補充

cname hlist art 進行 分組 遍歷 doc 查詢函數 標識

聚合查詢與分組查詢

聚合:aggregate(*args, **kwargs)

from django.db.models import Avg
Book.objects.all().aggregate(Avg(price))
{price__avg: 34.35}

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)}

分組:annotate()

為QuerySet中每一個對象都生成一個獨立的匯總值。

(1) 練習:統計每一本書的作者個數

bookList=Book.objects.annotate(authorsNum=Count(authors))
for book_obj in bookList:
    print(book_obj.title,book_obj.authorsNum)

(2) 如果想對所查詢對象的關聯對象進行聚合:

練習:統計每一個出版社的最便宜的書

publishList=Publish.objects.annotate(MinPrice=Min("book__price
")) for publish_obj in publishList: print(publish_obj.name,publish_obj.MinPrice)

annotate的返回值是QuerySet,如果不想遍歷對象,可以用上values_list:

queryResult= Publish.objects.annotate(MinPrice=Min("book__price")).values_list("name","MinPrice")
print(queryResult)

或:

queryResult=Book.objects.values("publish__name").annotate(MinPrice=Min(price))

註意:annotate內的字段即group by的字段

(3) 統計每一本以py開頭的書籍的作者個數:

 queryResult=Book.objects.filter(title__startswith="Py").annotate(num_authors=Count(authors))

(4) 統計不止一個作者的圖書:

queryResult=Book.objects.annotate(num_authors=Count(authors)).filter(num_authors__gt=1)

(5) 根據一本圖書作者數量的多少對查詢集QuerySet進行排序:

Book.objects.annotate(num_authors=Count(authors)).order_by(num_authors)

(6) 查詢各個作者出的書的總價格:

# 按author表的所有字段 group by
queryResult=Author.objects.annotate(SumPrice=Sum("book__price")).values_list("name","SumPrice")
    print(queryResult)
    
#按authors__name group by
queryResult2=Book.objects.values("authors__name").annotate(SumPrice=Sum("price")).values_list("authors__name","SumPrice")
print(queryResult2)

F查詢與Q查詢

F查詢

在上面所有的例子中,我們構造的過濾器都只是將字段值與某個常量做比較。如果我們要對兩個字段的值做比較,那該怎麽做呢?

Django 提供 F() 來做這樣的比較。F() 的實例可以在查詢中引用字段,來比較同一個 model 實例中兩個不同字段的值。

from django.db.models import F
Book.objects.filter(commnetNum__lt=F(keepNum))

Django 支持 F() 對象之間以及 F() 對象和常數之間的加減乘除和取模的操作

# 查詢評論數大於收藏數2倍的書籍
    Book.objects.filter(commnetNum__lt=F(keepNum)*2)

修改操作也可以使用F函數,比如將每一本書的價格提高30元:

Book.objects.all().update(price=F("price")+30) 

Q查詢

filter() 等方法中的關鍵字參數查詢都是一起進行“AND” 的。 如果你需要執行更復雜的查詢(例如OR 語句),你可以使用Q 對象。

from django.db.models import Q
Book.objects.filter(Q(title__startswith=‘Py‘))

Q 對象可以使用& 和| 操作符組合起來。當一個操作符在兩個Q 對象上使用時,它產生一個新的Q 對象。

bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))

等同於下面的SQL WHERE 子句:

WHERE name ="yuan" OR name ="egon"

你可以組合& 和| 操作符以及使用括號進行分組來編寫任意復雜的Q 對象。同時,Q 對象可以使用~ 操作符取反,這允許組合正常的查詢和取反(NOT) 查詢:

bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")

查詢函數可以混合使用Q 對象和關鍵字參數。所有提供給查詢函數的參數(關鍵字參數或Q 對象)都將"AND”在一起。但是,如果出現Q 對象,它必須位於所有關鍵字參數的前面。例如:

bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017), title__icontains="python")

Django之ORM-補充