Django ORM – 多表實例(聚合與分組查詢)

聚合查詢(aggregate)

聚合查詢函數(shù)是對一組值執(zhí)行計算,并返回單個值。

有表結構如下:

id title price publish_id pub_date
3 菜鳥教程 200.00 1 2010-10-10
4 沖靈劍法 100.00 1 2004-04-04

detail.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{{ res }}
</body>
</html>

計算所有圖書的平均價格:

from django.db.models import Avg,Max,Min,Count,Sum  #   引入函數(shù)
...
def add_book(request):
    res = models.Book.objects.aggregate(Avg("price"))
    return render(request, "detail.html", {"res": res});

// 輸出:{'price__avg': Decimal('150.000000')}

計算所有圖書的數(shù)量、最貴價格和最便宜價格:

res=models.Book.objects.aggregate(c=Count("id"),max=Max("price"),min=Min("price"))
// 輸出:{'c': 2, 'max': Decimal('200.00'), 'min': Decimal('100.00')}

小結:

  1. 聚合查詢返回值的數(shù)據(jù)類型是字典。不能再使用 QuerySet 數(shù)據(jù)類型的一些 API 了。
  2. 聚合函數(shù) aggregate() 是 QuerySet 的一個終止子句, 生成的一個匯總值,相當于 count()。日期數(shù)據(jù)類型(DateField)可以用 Max 和 Min。
  3. 返回的字典中:鍵的名稱默認是(屬性名稱加上__聚合函數(shù)名),值是計算出來的聚合值。
    如果要自定義返回字典的鍵的名稱,可以起別名:
    aggregate(別名 = 聚合函數(shù)名("屬性名稱"))

分組查詢(annotate)

分組查詢一般會用到聚合函數(shù)。

返回值:

  1. 分組后,用 values 取值,則返回值是 QuerySet 數(shù)據(jù)類型里面為一個個字典;
  2. 分組后,用values_list取值,則返回值是 QuerySet 數(shù)據(jù)類型里面為一個個元組。
    MySQL 中的 limit 相當于 ORM 中的 QuerySet 數(shù)據(jù)類型的切片。

annotate 里面放聚合函數(shù)。

  1. values 或者 values_list 放在 annotate 前面:values 或者 values_list 是聲明以什么字段分組,annotate 執(zhí)行分組。
  2. values 或者 values_list 放在annotate后面: annotate 表示直接以當前表的pk執(zhí)行分組,values 或者 values_list 表示查詢哪些字段, 并且要將 annotate 里的聚合函數(shù)起別名,在 values 或者 values_list 里寫其別名。

統(tǒng)計每一個出版社的最便宜的書的價格:

res = models.Publish.objects.values("name").annotate(in_price = Min("book__price"))

// 輸出:<QuerySet [{'name': '華山出版社', 'in_price': Decimal('100.00')}, {'name': '明教出版社', 'in_price': None}]>

統(tǒng)計每一本書的作者個數(shù)1:

res = models.Book.objects.annotate(c = Count("authors__name")).values("title","c")
// 輸出:<QuerySet [{'title': '菜鳥教程', 'c': 2}, {'title': '沖靈劍法', 'c': 1}]>

統(tǒng)計每一本書的作者個數(shù)2:values_list

res = models.Book.objects.annotate(c = Count("authors__name")).values_list("title","c")
// 輸出:<QuerySet [('菜鳥教程', 2), ('沖靈劍法', 1)]>

統(tǒng)計每一本以"菜"開頭的書籍的作者個數(shù):

models.Book.objects.filter(title__startswith="菜").annotate(c = Count("authors__name")).values("title","c")
// 輸出:<QuerySet [{'title': '菜鳥教程', 'c': 2}]>

統(tǒng)計不止一個作者的圖書名稱:

res = models.Book.objects.annotate(c = Count("authors__name")).filter(c__gt=1).values("title","c")
// 輸出:<QuerySet [{'title': '菜鳥教程', 'c': 2}]>

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

res = models.Book.objects.annotate(c = Count("authors__name")).order_by("-c").values("title","c")
// 輸出:<QuerySet [{'title': '菜鳥教程', 'c': 2}, {'title': '沖靈劍法', 'c': 1}]>

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

res = models.Author.objects.annotate(all = Sum("book__price")).values("name","all")
// 輸出:<QuerySet [{'name': '令狐沖', 'all': Decimal('300.00')}, {'name': '任我行', 'all': None}, {'name': '任盈盈', 'all': Decimal('200.00')}]>

小結:

  1. 使用 values => 字典,values_list => 元祖。
  2. value(或 value_list)在前,以values聲明的字段分組,在后以pk分組。

F() 查詢

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

F 動態(tài)獲取對象字段的值,可以進行運算。
Django 支持 F() 對象之間以及 F() 對象和常數(shù)之間的加減乘除和取余的操作。
修改操作(update)也可以使用 F() 函數(shù)。

查詢工資大于年齡的人:

from django.db.models import F
...
res = models.Emp.objects.filter(salary__gt=F("age")).values("name","age")
...

將每一本書的價格提高100元:

res = models.Book.objects.update(price=F("price")+100)

Q() 查詢

Q(條件判斷)
Q 對象可以使用 & | ~ (與 或 非)操作符進行組合。

查詢價格小于 150 或者名稱以菜開頭的書籍的名稱和價格。

rom django.db.models import Q
...
res=models.Book.objects.filter(Q(price__lt=150)|Q(title__startswith="菜")).values("title","price")
// 輸出:<QuerySet [{'title': '菜鳥教程', 'price': Decimal('200.00')}, {'title': '沖靈劍法', 'price': Decimal('100.00')}]>

查詢以"菜"結尾或者不是 2010 年 10 月份的書籍:

res = models.Book.objects.filter(Q(title__endswith="菜") | ~Q(Q(pub_date__year=2010) & Q(pub_date__month=10)))
// 輸出:<QuerySet [{'title': '沖靈劍法', 'price': Decimal('100.00')}]>

查詢出版日期是 2004 或者 1999 年,并且書名中包含有"菜"的書籍。
Q 對象和關鍵字混合使用,Q 對象要在所有關鍵字的前面:

res = models.Book.objects.filter(Q(pub_date__year=2004) | Q(pub_date__year=1999), title__contains="菜")
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容