目錄
- 正反向查詢進階操作
- 聚合查詢
- 1.使用聚合函式之前需要匯入模塊
- 2.聚合函式的使用
- 3.關鍵字aggregate
- 分組查詢
- 1.分組查詢
- 2.回傳值
- 3.分組查詢關鍵字
- 分組練習題
- F與Q查詢
- F查詢
- Q查詢
- Q查詢的進階用法
- ORM查詢優化
- 1.ORM查詢優化之only(單表)
- 2.ORM查詢優化之defer(單表)
- 3.ORM查詢優化之select_related(多表)
- 4.ORM查詢優化之prefetch_related(多表)
- 額外補充個知識:當表中已經有資料的情況下 添加新的欄位需要指定一些引數
- 報錯問題
正反向查詢進階操作
'''正反向查詢進階操作'''
# 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停止了服務
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/505350.html
標籤:架構設計
