聚合分組查詢、F與Q查詢、常用欄位知識
今日內容概要
-
max、min、sum、count、avg
-
分組查詢(group by的使用)annotate
-
F與Q查詢
-
django中如何開啟事務
-
orm中常用欄位及引數
-
資料庫查詢優化(only與defer、select_related與prefetch_related)
-
"""
聚合查詢通常情況下都是配合分組一起使用的,只要是跟資料庫相關的模組 ,基本上都在django.db.models裡面,如果上述沒有那麼應該在django.db裡面
"""
#聚合查詢 aggregatefrom django.db.models import Max,Min,Sum,Avg,Count #所有書的平均價格 res = models.Book.objects.aggregate(Avg('price')) # print(res) res = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Count('pk'), Avg('price')) print(res)
分組查詢
# 分組查詢 annotate # 1.統計每一本書的作者個數res = models.Book.objects.annotate(author_num = Count('author')).values('title','author_num') print(res) #2.正常情況下應該是需要在Count內部的author後面加上__id,因為是反向查詢,需要跨表到作者表中去查個數,如下所示,但是orm自動簡化,只需要寫author即可 res = models.Book.objects.annotate(author_num = Count('author__id')).values('title','author_num') print(res)#統計每個出版社賣的最便宜的書的價格 res = models.Publish.objects.annotate(min_price = Min('book__price')).values('name','min_price') print(res) # 3.統計不止一個作者的圖書 # """ # 只要你的orm語句得出的結果還是一個queryset物件 # 那麼它就可以繼續無限制的點queryset物件封裝的方法 # """ res = models.Book.objects.annotate(author_num = Count('author')).filter(author_num__gt=1).values('title','author_num') print(res) # 4.查詢每個作者出的書的總價格 res = models.Author.objects.annotate(price_sum = Sum('book__price')).values('name','price_sum') print(res) #補充幾個額外的知識點: #1.如果我想按照指定的欄位分組該如何處理呢? # models.Book.objects.values('price').annotate() 先將要指定的欄位拿出來,再進行分組 #2.你們的機器上如果出現分組查詢報錯的情況怎麼辦?你需要修改資料庫嚴格模式
F與Q查詢
# F查詢 """ 能夠幫助你直接獲取到表中某個欄位對應的資料 """ #1.查詢賣出數大於庫存數的書籍 from django.db.models import F # #不需要查詢兩次,先查詢書籍的賣出數,再查詢庫存數,然年後將兩者進行比較。利用F查詢可以直接將要查詢的欄位的資料拿出 # res = models.Book.objects.filter(maichu__gt=F('kucun')) # print(res) # 2.將所有書籍的價格提升100塊 res = models.Book.objects.update(price = F('price')+100) # 3.將所有書的名稱後面加上爆款兩個字 """ 在操作字元型別的資料的時候 F不能夠直接做到字串的拼接 """ from django.db.models.functions import Concat from django.db.models import Value #利用Concat和Value完成字串的拼接 models.Book.objects.update(title = Concat(F('title'),Value('爆款'))) # models.Book.objects.update(title=F('title') + '爆款') # 所有的名稱會全部變成空白
#Q查詢 from django.db.models import Q #(與 ,) (或 |) (非 ~) #1.查詢賣出數大於100或者價格小於600的書籍 #res = models.Book.objects.filter(maichu__gt=100,price__lt=600) 無法查詢,因為filter後引數還是and關係 # # res = models.Book.objects.filter(Q(maichu__gt=100),Q(price__lt=600))#Q包裹逗號分割 還是and關係 # res = models.Book.objects.filter(Q(maichu__gt=100) | Q(price__lt=600)) # | or關係 # res = models.Book.objects.filter(~Q(maichu__gt=100) | Q(price__lt=600)) # ~ not關係 # Q的高階用法 能夠將查詢條件的左邊也變成字串的形式 q = Q() q.connector = 'or' q.children.append(('maichu__gt', 100)) q.children.append(('price__lt', 600)) res = models.Book.objects.filter(q) # 預設還是and關係 print(res)
django中如何開啟事務
首先複習一下mysql中事物的四大特性:ACID A:原子性 C:一致性 I:隔離性 D:永續性 事物的回滾:roolback 事物的確認:commit,目前我們只需要學習如何在django中開啟事務
from django.db import transaction try: with transaction.atomic(): #sql1 ... #sql2 except Exception as e: print(e) print('執行其他操作')
ORM中常用的欄位及引數
AutoField 主鍵欄位 primary_key=True CharField varchar verbose_name 欄位的註釋
max_length 長度
IntegerField int BigIntegerField bigint DecimalField max_digits=8 decimal_places=2 EmailFiled varchar(254) DateField date DateTimeField datetime auto_now:每次修改資料的時候都會自動更新當前時間 auto_now_add:只在建立資料的時候記錄建立時間後續不會自動修改了 BooleanField(Field) - 布林值型別 該欄位傳佈爾值(False/True) 資料庫裡面存0/1 TextField(Field) - 文字型別 該欄位可以用來存大段內容(文章、部落格...) 沒有字數限制 後面的bbs作業 文章欄位用的就是TextField FileField(Field) - 字元型別 upload_to = "/data" 給該欄位傳一個檔案物件,會自動將檔案儲存到/data目錄下然後將檔案路徑儲存到資料庫中(/data/a.txt) 後面bbs作業也會涉及 # 更多欄位 直接參考部落格:https://www.cnblogs.com/Dominic-Ji/p/9203990.html
django中自定義欄位:
class My_field(models.Field): def __init__(self, max_length, *args, **kwargs): self.max_length = max_length # 呼叫父類的init方法 super().__init__(max_length=max_length,*args,**kwargs)# 呼叫父類的init方法 def db_type(self, connection): return 'char(%s)' % self.max_length
# 外來鍵欄位及引數
unique=True
ForeignKey(unique=True) === OneToOneField()
# 你在用前面欄位建立一對一 orm會有一個提示資訊 orm推薦你使用後者但是前者也能用
db_index
如果db_index=True 則代表著為此欄位設定索引
(複習索引是什麼)
to_field
設定要關聯的表的欄位 預設不寫關聯的就是另外一張的主鍵欄位
on_delete
當刪除關聯表中的資料時,當前表與其關聯的行的行為。
"""
django2.X及以上版本 需要你自己指定外來鍵欄位的級聯更新級聯刪除
"""
資料庫查詢優化
only與defer
select_related與prefetch_related
"""
orm語句的特點:
惰性查詢
如果你僅僅只是書寫了orm語句 在後面根本沒有用到該語句所查詢出來的引數
那麼orm會自動識別 直接不執行
"""
# only與defer # res = models.Book.objects.all() # print(res) # 要用資料了才會走資料庫 # 想要獲取書籍表中所有數的名字 # res = models.Book.objects.values('title') # for d in res: # print(d.get('title')) # 你給我實現獲取到的是一個數據物件 然後點title就能夠拿到書名 並且沒有其他欄位 # res = models.Book.objects.only('title') # res = models.Book.objects.all() # print(res) # <QuerySet [<Book: 三國演義爆款>, <Book: 紅樓夢爆款>, <Book: 論語爆款>, <Book: 聊齋爆款>, <Book: 老子爆款>]> # for i in res: # print(i.title) # 點選only括號內的欄位 不會走資料庫 # print(i.price) # 點選only括號內沒有的欄位 會重新走資料庫查詢而all不需要走了 res = models.Book.objects.defer('title') # 物件除了沒有title屬性之外其他的都有 for i in res: print(i.price) """ defer與only剛好相反 defer括號內放的欄位不在查詢出來的物件裡面 查詢該欄位需要重新走資料 而如果查詢的是非括號內的欄位 則不需要走資料庫了 """ # select_related與prefetch_related # select_related與prefetch_related 跟跨表操作有關 # res = models.Book.objects.all() # for i in res: # print(i.publish.name) # 每迴圈一次就要走一次資料庫查詢 # res = models.Book.objects.select_related('authors') # INNER JOIN """ select_related內部直接先將book與publish連起來 然後一次性將大表裡面的所有資料 全部封裝給查詢出來的物件 這個時候物件無論是點選book表的資料還是publish的資料都無需再走資料庫查詢了 select_related括號內只能放外來鍵欄位 一對多 一對一 多對多也不行 """ # for i in res: # print(i.publish.name) # 每迴圈一次就要走一次資料庫查詢 res = models.Book.objects.prefetch_related('publish') # 子查詢 """ prefetch_related該方法內部其實就是子查詢 將子查詢查詢出來的所有結果也給你封裝到物件中 給你的感覺好像也是一次性搞定的 """ for i in res: print(i.publish.name)