正反向查詢進階操作 '''正反向查詢進階操作''' # 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')}
res1 = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Avg('price'), Count('pk'))
print(res1)
分組查詢
報錯原因
打開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}]>
"""
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')}]>
"""
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)
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')}]>
"""
F與Q查詢
F查詢
能夠幫助你直接獲取到列表中某個欄位對應的數據
註意:
在操作字元串類型的數據的時候, F不能夠直接做到字元串的拼接
1.查詢賣出書大於庫存數的書籍
res = models.Book.objects.filter(storage_num__gt=F('sale_num'))
print(res)
將所有書籍的價格上漲1000快
res = models.Book.objects.update(price=F('price') + 1000)
給所有書籍名稱後面加上爆款尾碼
針對字元串數據無法直接拼接
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('~爆款')))
Q查詢
可以改變filter括弧內多個條件之間的邏輯運算符,還可以將查詢的結果改為字元串形式
filter()等方法中的關鍵字參數查詢都是一起進行"and",如果你需要執行更複雜的查詢(列如ORM語句),你可以使用Q對象。
查詢賣出數大於100並且價格小於60的書籍
res = models.Book.objects.filter(Q(sale_num__gt=100), Q(price__lt=600))
print(res)
查詢賣出數大於130或者價格小於30的書籍
res = models.Book.objects.filter(Q(sale_num__gt=130) | Q(price__lt=30))
print(res)
查詢賣出數不是大於80或者價格大於600的書籍
res = models.Book.objects.filter(~Q(sale_num__gt=80) | Q(price__gt=600))
print(res)
總結
, 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)
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查詢的話 儘量不要去點括弧內沒有的欄位 因為它每次都會去查詢一次
"""
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剛好相反
數據對象點擊括弧內出現的欄位 每次都會走資料庫查詢
數據對象點擊括弧內沒有的字典 不會走資料庫查詢
"""
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括弧內只能接收外鍵欄位(一對多 一對一) 它會在內部自動拼表 得出的數據對象在點擊表中數據的時候都不會再走資料庫查詢
"""
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)
額外補充個知識:當表中已經有數據的情況下 添加新的欄位需要指定一些參數
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)")
解決方法:查看資料庫是否啟動,導致這個錯誤很可能是MySQL停止了服務