正反向查詢進階操作、聚合查詢、分組查詢、F與Q查詢、ORM查詢優化

来源:https://www.cnblogs.com/zxr1002/archive/2022/09/06/16663198.html
-Advertisement-
Play Games

正反向查詢進階操作 '''正反向查詢進階操作''' # 1.查詢主鍵為1的書籍對應的出版社名稱及書名 res = models.Publish.objects.filter(book__pk=1).values('name', 'book__title') print(res) # <QuerySe ...


目錄

正反向查詢進階操作

    '''正反向查詢進階操作'''
    # 1.查詢主鍵為1的書籍對應的出版社名稱及書名
    res = models.Publish.objects.filter(book__pk=1).values('name', 'book__title')
    print(res)  # <QuerySet [{'name': '清華大學出版社', 'book__title': '女人你成功引起了我的註意'}]>

    # 2.查詢主鍵為3的書籍對應的作者姓名及書名
    res1 = models.Author.objects.filter(book__pk=3).values('name', 'book__title')
    print(res1)  # <QuerySet [{'name': 'jfw', 'book__title': '涼生,我們可不可以不憂傷'}]>

    # 3.查詢zxb的作者的電話號碼和地址
    res2 = models.AuthorDetail.objects.filter(author__name='zxb').values('phone', 'addr')
    print(res2)  # <QuerySet [{'phone': 119, 'addr': '浙江'}]>

    # 4.查詢東方出版社出版的書籍名稱和價格
    res4 = models.Book.objects.filter(publish__name='東方出版社').values('title', 'price')
    print(res4)  # <QuerySet [{'title': '桃疆', 'price': Decimal('14.67')}, {'title': '三生三十十里桃花', 'price': Decimal('35.98')}, {'title': '玄霜', 'price': Decimal('54.21')}]>

    # 5.查詢zxr寫過的書的名稱和日期
    res5 = models.Book.objects.filter(author__name='zxb').values('title', 'publish_time')
    print(res5)  # <QuerySet [{'title': '女人你成功引起了我的註意', 'publish_time': datetime.datetime(2022, 9, 5, 13, 16, 43, 303992, tzinfo=<UTC>)}]>

    # 6.查詢電話是110的作者姓名和年齡
    res6 = models.Author.objects.filter(author_detail__phone=110).values('name', 'age')
    print(res6)  # <QuerySet [{'name': 'zxr', 'age': 18}]>

    # 7.查詢主鍵為1的書籍對應的作者電話號碼
    res7 = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')
    print(res7)  # <QuerySet [{'phone': 120}, {'phone': 119}]>
    res8 = models.Author.objects.filter(book__pk=1).values('author_detail__phone')
    print(res8)  # <QuerySet [{'author_detail__phone': 120}, {'author_detail__phone': 119}]>

聚合查詢

聚合函數:max、min、sum、avg、count

1.使用聚合函數之前需要導入模塊

from django.db.models import Max, Min, Sum, Avg, Count

2.聚合函數的使用

聚合函數通常情況下是配合分組一起使用的

3.關鍵字aggregate

沒有分組之前如果單純的使用聚合函數 需要關鍵字aggregate

# 1.查詢所有書的平均價格
res = models.Book.objects.aggregate(Avg('price'))
print(res)  # {'price__avg': Decimal('183.117778')}

image

res1 = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Avg('price'), Count('pk'))
print(res1)

image

分組查詢

image
報錯原因
image

打開MySQL
輸入>>>:show variables like '%mode%';

分組有一個特性 預設只能夠直接獲取分組的欄位 其他欄位需要使用方法
我們也可以忽略掉該特性 將sql_mode中only_full_group_by配置移除即可
# 示例1:統計每一本書的作者個數
res = models.Book.objects.annotate(author_num=Count('author__pk')).values('title', 'author_num')
print(res)

"""
    1.按照整條數據分組
        models.Book.objects.annotate()  按照一條條書籍記錄分組
    2.按照表中某個欄位分組()
        models.Book.objects.values('title').annotate()  按照annotate之前values括弧中指定的欄位分組
"""

"""
<QuerySet [{'title': '女人你成功引起了我的註意爆款~爆款', 'author_num': 2},
{'title': '涼生,我們可不可以不憂傷爆款~爆款', 'author_num': 1},
{'title': '桃疆爆款~爆款', 'author_num': 2},
{'title': '我是你的,生生世世爆款~爆款', 'author_num': 2},
{'title': '國民大偵探爆款~爆款', 'author_num': 1},
{'title': '十宗罪爆款~爆款', 'author_num': 1},
{'title': '三生三十十里桃花爆款~爆款', 'author_num': 1},
{'title': '玄霜爆款~爆款', 'author_num': 1},
{'title': '一生一世爆款~爆款', 'author_num': 1}]>
"""

1.分組查詢

annotate()為調用的QuerySet中每一個對象都生成一個獨立的統計值(統計方法用聚合函數,所有使用前要從django.db.models引入Avg,Max,Count,Sum(首字母大寫))。

2.返回值

分組後,用values取值,則返回值是QuerySet書籍類型裡面為一個個字典
分組後,用values_list取值,則返回值是QuerySet數據類型裡面為一個個元組

MySQL中的limit相當於ORM中的QuerySet數據類型的切片。

3.分組查詢關鍵字

annotate()  裡面放聚合函數

1.values 或者 values_list 放在 annotate 前面:values 或者 values_list 是聲明以什麼欄位分組,annotate 執行分組。
2.values 或者 values_list 放在annotate後面: annotate 表示直接以當前表的pk執行分組,values 或者 values_list 表示查詢哪些欄位, 並且要將 annotate 里的聚合函數起別名,在 values 或者 values_list 里寫其別名。
3.filter放在 annotate 前面:表示where條件
4.filter放在annotate後面:表示having

跨表分組查詢本質就是將關聯表join成一張表,再按單表的思路進行分組查詢

分組練習題

models後面點什麼 就按什麼分組 

author_num 是我們自己定義的欄位 用來存儲統計出來的每本書對應的作者個數

1.統計每一本書的作者個數

res = models.Book.objects.annotate(author_num=Count('author__pk')).values('title', 'author_num')
print(res)
res1 = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num')
print(res1)
"""
    1.按照整條數據分組
        models.Book.objects.annotate()  按照一條條書籍記錄分組
    2.按照表中某個欄位分組()
        models.Book.objects.values('title').annotate()  按照annotate之前values括弧中指定的欄位分組
"""
"""
<QuerySet [{'title': '女人你成功引起了我的註意', 'author_num': 2},
{'title': '涼生,我們可不可以不憂傷', 'author_num': 1},
{'title': '桃疆', 'author_num': 2},
{'title': '我是你的,生生世世', 'author_num': 2},
{'title': '國民大偵探', 'author_num': 1},
{'title': '十宗罪', 'author_num': 1},
{'title': '三生三十十里桃花', 'author_num': 1},
{'title': '玄霜', 'author_num': 1},
{'title': '一生一世', 'author_num': 1}]>
"""

image

2.統計每個出版社賣的最便宜的書的價格

res1 = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
print(res1)
"""
<QuerySet [{'name': '清華大學出版社',
'min_price': Decimal('28.98')},
{'name': '北方出版社', 'min_price': Decimal('34.98')},
{'name': '南方出版社', 'min_price': Decimal('56.29')},
{'name': '東方出版社', 'min_price': Decimal('14.67')}]>
"""

image
3.統計不止一個作者的圖書

'''filter在annotate前面則是where 在annotate後面則是having'''
res = models.Book.objects.annotate(author_num=Count('author__pk')).filter(author_num__gt=1).values('title', 'author_num')
print(res)

image
4.查詢各個作者出的書的總價格

res = models.Author.objects.annotate(book_sum_price=Sum('book__price')).values('name', 'book_sum_price')
print(res)

"""
<QuerySet [{'name': 'zxr', 'book_sum_price': Decimal('159.25')},
{'name': 'wyn', 'book_sum_price': Decimal('1365.63')},
{'name': 'zxb', 'book_sum_price': Decimal('1383.86')},
{'name': 'jfw', 'book_sum_price': Decimal('103.95')}]>
"""

image

F與Q查詢

F查詢

能夠幫助你直接獲取到列表中某個欄位對應的數據

註意:
在操作字元串類型的數據的時候, F不能夠直接做到字元串的拼接

1.查詢賣出書大於庫存數的書籍

res = models.Book.objects.filter(storage_num__gt=F('sale_num'))
print(res)

image
將所有書籍的價格上漲1000快

res = models.Book.objects.update(price=F('price') + 1000)

image
image
給所有書籍名稱後面加上爆款尾碼
針對字元串數據無法直接拼接
image

models.Book.objects.filter().all().update(title=F('title') + '爆款')  # 針對字元串數據無法直接拼接
    # 導入Concat模塊
    from django.db.models.functions import Concat
    # 導入Value模塊
    from django.db.models import Value
    models.Book.objects.filter().all().update(title=Concat(F('title'), Value('~爆款')))

image

Q查詢

可以改變filter括弧內多個條件之間的邏輯運算符,還可以將查詢的結果改為字元串形式

filter()等方法中的關鍵字參數查詢都是一起進行"and",如果你需要執行更複雜的查詢(列如ORM語句),你可以使用Q對象。

查詢賣出數大於100並且價格小於60的書籍

res = models.Book.objects.filter(Q(sale_num__gt=100), Q(price__lt=600))
print(res)

image

查詢賣出數大於130或者價格小於30的書籍

res = models.Book.objects.filter(Q(sale_num__gt=130) | Q(price__lt=30))
print(res)

image

查詢賣出數不是大於80或者價格大於600的書籍

res = models.Book.objects.filter(~Q(sale_num__gt=80) | Q(price__gt=600))
print(res)

image
總結

,               and關係
|               or關係
~               not關係

Q 預設是and,可以進行修改
    q = Q()
    q.connector = 'or'

Q查詢的進階用法

可以將查詢的結果改為字元串形式

先產生一個對象
    q = Q()
修改預設的對象
    q.connector = 'or'
添加查詢條件,第一個寫一個字元串的欄位名 第二個元素寫一些具體的數值
    q.children.append(('pk', 1))
    q.children.append(('publish_id', 3))
添加好以後q對象支持直接用filter進行篩選
    res = models.Book.objects.filter(q)
    print(res)

image

image

ORM查詢優化

django orm預設都是惰性查詢
    當orm的語句在後續的代碼中真正需要使用的時候才會執行
django orm自帶limit分頁
    減輕資料庫端以及服務端的壓力

1.ORM查詢優化之only(單表)

res = models.Book.objects.only('title','price')
for obj in res:
     print(obj.title)
     print(obj.price)
     print(obj.publish_time)
    """
    only會將括弧內填寫的欄位封裝成一個個數據對象 對象在點擊的時候不會再走資料庫查詢
    但是對象也可以點擊括弧內沒有的欄位 只不過每次都會走資料庫查詢 
    如果看到有人只有only查詢的話 儘量不要去點括弧內沒有的欄位 因為它每次都會去查詢一次
    """

image
image

2.ORM查詢優化之defer(單表)

res = models.Book.objects.defer('title', 'price')
for obj in res:
    # print(obj.title)
    # print(obj.price)
    print(obj.publish_time)
    """
    defer與only剛好相反
        數據對象點擊括弧內出現的欄位 每次都會走資料庫查詢
        數據對象點擊括弧內沒有的字典 不會走資料庫查詢
    """

image

3.ORM查詢優化之select_related(多表)

res = models.Book.objects.all()
for obj in res:
     print(obj.publish.name)  # 頻繁走資料庫查詢

res = models.Book.objects.select_related('publish')
"""
    select_related括弧內只能接收外鍵欄位(一對多 一對一) 它會在內部自動拼表 得出的數據對象在點擊表中數據的時候都不會再走資料庫查詢
"""

image
image

4.ORM查詢優化之prefetch_related(多表)

for obj in res:
     print(obj.publish.name)
"""
    prefetch_related底層其實是子查詢 將查詢之後的結果也一次性封裝到數據對象中 用戶在使用的時候是感覺不出來的
"""
res = models.Book.objects.prefetch_related('publish')
for obj in res:
    print(obj.publish.name)

image

額外補充個知識:當表中已經有數據的情況下 添加新的欄位需要指定一些參數

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish_time = models.DateTimeField(auto_now=True)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    author = models.ManyToManyField(to='Author')
    '''
    當表中已經有數據的情況下 添加新的欄位需要指定一些參數
        1.設置欄位值存於為空    null=True
        2.設置欄位預設值    default=1000
        3.在終端直接給出預設值
    '''
    storage_num = models.IntegerField(verbose_name='庫存數', null=True)
    sale_num = models.IntegerField(verbose_name='賣出數目', default=1000)

    def __str__(self):
        return f'對象:{self.title}'

報錯問題

django.db.utils.OperationalError: (2002, "Can't connect to server on '127.0.0.1' (10061)")
image
解決方法:查看資料庫是否啟動,導致這個錯誤很可能是MySQL停止了服務


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 每日3題 22 以下代碼執行後,控制臺中的輸出內容為? var a = [1, 2, 3]; a.join = a.shift; console.log(a == 1 && a == 2 && a == 3); 23 以下代碼執行後,控制臺中的輸出內容為? var arr = [0, 1]; arr ...
  • 公共樣式: <style> * { margin: 0; padding: 0; } .has-flex { display: flex; } </style> 垂直居中 子元素左右分佈 css .father-one { width: 100%; height: 200px; background ...
  • vue簡介 1.vue是什麼 一套用於構建用戶界面的漸進式javascript框架 構建用戶界面:拿到的數據轉換為用戶可以看到的數據 漸進式:vue可以自底向上逐層用 從一個輕量小巧的庫逐漸遞進到使用各式各樣的vue插件 2.vue開發者(老二次元了,哈哈) 2013 | 受到Angular的啟發, ...
  • JavaScript 鉤子 點擊打開視頻講解更加詳細 可以在 attribute 中聲明 JavaScript 鉤子 完整案例: <template> <div id="app"> <div id="example-3"> <button @click="show = !show"> Toggle ...
  • 自定義一個類似jquer庫==> Hq庫的具體步驟: // 1.通過$_$('div')方法就可以直接返回一個由Hq構造函數實例化出來的一個對象 // 2.在通過Hq構造函數,獲取你以選擇器為參數的所有節點 // 3.Hq在調用原型上addEles方法將所有的節點,賦值給對應的this的每一項(實例 ...
  • 使用three.js(webgl)搭建智慧樓宇、3D定位、三維室內定位、設備檢測、數字孿生、物聯網3D、物業3D監控、物業基礎設施可視化運維、3d建築,3d消防,消防演習模擬,3d庫房,webGL,threejs,3d機房,bim管理系統 ...
  • js實現將excel表格copy到頁面 點擊打開視頻講解更加詳細 其實最核心的技術,還是copy的是我們粘貼板上的數據 就像平常怎麼粘貼複製其他的數據一樣,只是我們在excel粘貼的是一個表格數據 這時我們首先也時獲取我們粘貼板上的數據,如何對粘貼板上的數據進行處理,處理成 我們想要的表格形式。 完 ...
  • 蒼穹之邊,浩瀚之摯,眰恦之美; 悟心悟性,善始善終,惟善惟道! —— 朝槿《朝槿兮年說》 寫在開頭 對於Java領域中的鎖,其實從接觸Java至今,我相信每一位Java Developer都會有這樣的一個感覺?不論是Java對鎖的實現還是應用,真的是一種“群英薈萃”,而且每一種鎖都有點各有各的驢,各 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...