聚合查詢(aggregate)
# 聚合查詢 """ 聚合查詢通常情況下都是配合分組一起使用的 只要是跟數據庫相關的模塊 基本上都在django.db.models里面 如果上述沒有那么應該在django.db里面 """ from app01 import models from django.db.models import Max,Min,Sum,Count,Avg # 1 所有書的平均價格 # res = models.Book.objects.aggregate(Avg('price')) # print(res) # 2.上述方法一次性使用 res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('pk'),Avg('price')) print(res)
分組查詢 annotate
""" MySQL分組查詢都有哪些特點 分組之后默認只能獲取到分組的依據 組內其他字段都無法直接獲取了 嚴格模式 ONLY_FULL_GROUP_BY """ from django.db.models import Max, Min, Sum, Count, Avg # 1.統計每一本書的作者個數 res = models.Book.objects.annotate() # models后面點什么 就是按什么分組 res = models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num') """ author_num是我們自己定義的字段 用來存儲統計出來的每本書對應的作者個數 """ res1 = models.Book.objects.annotate(author_num=Count('authors__id')).values('title','author_num') print(res,res1) """ 代碼沒有補全 不要怕 正常寫 補全給你是pycharm給你的 到后面在服務器上直接書寫代碼 什么補全都沒有 顏色提示也沒有 """ # 2.統計每個出版社賣的最便宜的書的價格(作業:復習原生SQL語句 寫出來) res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price') print(res) # 3.統計不止一個作者的圖書 # 1.先按照圖書分組 求每一本書對應的作者個數 # 2.過濾出不止一個作者的圖書 res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num') # """ # 只要你的orm語句得出的結果還是一個queryset對象 # 那么它就可以繼續無限制的點queryset對象封裝的方法 # # """ print(res) # 4.查詢每個作者出的書的總價格 res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price') print(res) """ 如果我想按照指定的字段分組該如何處理呢? models.Book.objects.values('price').annotate() 后續BBS作業會使用 你們的機器上如果出現分組查詢報錯的情況 你需要修改數據庫嚴格模式 """
F查詢
# 1.查詢賣出數大于庫存數的書籍 # F查詢 """ 能夠幫助你直接獲取到表中某個字段對應的數據 """ from django.db.models import F res = models.Book.objects.filter(maichu__gt=F('kucun')) print(res) # 2.將所有書籍的價格提升500塊 models.Book.objects.update(price=F('price') + 500) # 3.將所有書的名稱后面加上爆款兩個字 """ 在操作字符類型的數據的時候 F不能夠直接做到字符串的拼接 """ from django.db.models.functions import Concat from django.db.models import Value models.Book.objects.update(title=Concat(F('title'), Value('爆款'))) models.Book.objects.update(title=F('title') + '爆款') # 所有的名稱會全部變成空白
Q查詢
# Q查詢 # 1.查詢賣出數大于100或者價格小于600的書籍 res = models.Book.objects.filter(maichu__gt=100,price__lt=600) """filter括號內多個參數是and關系""" from django.db.models import Q 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關系 # print(res) # <QuerySet []> # 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中如何開啟事務
- 事務
- ACID
原子性
- 不可分割的最小單位
一致性
- 跟原子性是相輔相成
隔離性
- 事務之間互相不干擾
持久性
- 事務一旦確認永久生效
- 事務的回滾
- rollback
- 事務的確認
- commit
# 事務 from django.db import transaction try: with transaction.atomic(): # sql1 # sql2 ... # 在with代碼快內書寫的所有orm操作都是屬于同一個事務 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作業也會涉及 # 更多字段 直接參考博客:http://www.rzrgm.cn/Dominic-Ji/p/9203990.html # django除了給你提供了很多字段類型之外 還支持你自定義字段 class MyCharField(models.Field): def __init__(self,max_length,*args,**kwargs): self.max_length = max_length # 調用父類的init方法 super().__init__(max_length=max_length,*args,**kwargs) # 一定要是關鍵字的形式傳入 def db_type(self, connection): """ 返回真正的數據類型及各種約束條件 :param connection: :return: """ return 'char(%s)'%self.max_length # 自定義字段使用 myfield = MyCharField(max_length=16,null=True) # 外鍵字段及參數 unique=True ForeignKey(unique=True) === OneToOneField() # 你在用前面字段創建一對一 orm會有一個提示信息 orm推薦你使用后者但是前者也能用 db_index 如果db_index=True 則代表著為此字段設置索引 (復習索引是什么) to_field 設置要關聯的表的字段 默認不寫關聯的就是另外一張的主鍵字段 on_delete 當刪除關聯表中的數據時,當前表與其關聯的行的行為。 """ django2.X及以上版本 需要你自己指定外鍵字段的級聯更新級聯刪除 """
數據庫查詢優化
only與defer
""" 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
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)
總結
only跟get取值的區別是get獲取的值是獲取的是列表套字典,all(),因為他獲取了全部數據,如果要查指定字段的化用only和defer比較好與get獲取的值是區別是對象
prefetch_related該方法內部其實就是子查詢
將子查詢查詢出來的所有結果也給你封裝到對象中
給你的感覺好像也是一次性搞定的
給的數據不是一次性給完的,如果跨表查詢還是回重新查詢另一個的數據
兩種方法各優勢
select_related:# 一次就要走數據庫查詢數據,這樣就不用查一次數據就走一次數據庫了
如果要多次取數據,比較推薦這種
prefetch_related:獲取的一張表的數據,如果字段較多且要第二張表進行過濾
就比較推薦這種方法
將子查詢查詢出來的所有結果也給你封裝到對象中
給你的感覺好像也是一次性搞定的
給的數據不是一次性給完的,如果跨表查詢還是回重新查詢另一個的數據
兩種方法各優勢
select_related:# 一次就要走數據庫查詢數據,這樣就不用查一次數據就走一次數據庫了
如果要多次取數據,比較推薦這種
prefetch_related:獲取的一張表的數據,如果字段較多且要第二張表進行過濾
就比較推薦這種方法
浙公網安備 33010602011771號