Django框架:8、聚合查詢、分組查詢、F與Q查詢、ORM查詢最佳化、ORM事務操作、ORM常用欄位型別、ORM常用欄位引數

kngk發表於2022-12-19

Django 資料庫

一、聚合查詢

聚合函式:

  • Max
    • 求最大值
  • Min
    • 求最小值
  • Sun
    • 求和
  • Cont
    • 統計數量
  • Avg
    • 求平均值

使用方法

  • 類名.object.aggreate(聚合函式(‘欄位名’))

​ 在MySQL資料庫中,聚合函式需要在分組後(group by)才能使用

​ 在Django中,可以直接使用,需要搭配關鍵詞:aggtegate

1、匯入模組
	from django.db.models import Max,Min,Sun,Count,Avg
    
2、res = Book.objects.aggregate(Max('price'), Count('pk'), 最小价格=Min('price'), allPrice=Sum('price'),平均價格=Avg('price'))

二、分組查詢

補充

問題:
	在執行orm分組查詢中,如果報錯,並且有關鍵字sql_mode strict mode
    
解決方法:
	移除sql_mode中的only_full_group_by

使用方法

  • 按表分組
    • models.表名.objects.annotate()
  • 按指定欄位分組
    • models.表名.objects.values('欄位名').annotate()

按表分組

# 分組查詢
    # 統計每一本書的作者個數
    # res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num')
    # print(res)
    # 統計出每個出版社賣的最便宜的書的價格
    # res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
    # print(res)
    # 統計不止一個作者的圖書
    # 1.先統計每本書的作者個數
    # res = models.Book.objects.annotate(author_num=Count('authors__pk'))
    # 2.篩選出作者個數大於1的資料
    # res = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gt=1).values('title',
    #                                                                                                     'author_num')
    # print(res)
    # 查詢每個作者出的書的總價格
    # res = models.Author.objects.annotate(總價=Sum('book__price'),count_book=Count('book__pk')).values('name','總價','count_book')
    # print(res)

按欄位分組

res = models.Book.objects.values('publish_id').annotate(count_pk=Count('pk')).values('publish_id', 'count_pk')
    print(res)

三、F查詢與Q查詢

1、F查詢

​ 當查詢條件不是明確的,也需要從資料庫中獲取,就需要使用F查詢,它可以直接對一整個欄位下的資料進行操作

使用方法

1、匯入模組
	from django.db.models import F
  
2、具體用法
	# 1.查詢庫存數大於賣出數的書籍
	# res  = models.Book.objects.filter(kucun__gt=F('maichu'))
	
    # 2.將所有書的價格漲800
    # models.Book.objects.update(price=F('price') + 800)	
    # 3.將所有書的名稱後面追加爆款
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title'), Value('新款')))

2、Q查詢

​ ORM中,所有的資料條件都是使用逗號隔開,彼此的關係預設都是and的關係

​ Q:可以將多個查詢條件的關係做修改

使用方法

1、匯入模組
	from django.db.models import Q
    
2、具體用法
	# and關係
    models.Book.objects.filter(Q(pk=1),Q(title='三國'))  
    
    # or關係
    models.Book.objects.filter(Q(pk=1) | Q(title='三國'))
    
    # not關係
    models.Book.objects.filter(~Q(pk=1),Q(title='三國')) 

3、Q查詢進階操作

說明

​ 透過生成Q物件,並提前設定好條件,直接將Q物件傳入filter中當作條件進行查詢

具體用法

1、匯入Q模組
	from django.db.models import Q
    
 2、產生Q物件
	q_obj = Q()
 
3、設定連結條件(預設為and,可以修改為or)
	q_obj.connector = 'or'

4、新增查詢條件 (支援新增多個查詢條件)
	# 查詢條件1
	q_obj.children.append(('pk', 1))
 	# 查詢條件2
	q_obj.children.append(('price__gt', 2000)) 
 
5、傳入Q物件,進行查詢(# 查詢支援直接填寫q物件)
	res = models.Book.objects.filter(q_obj) 
	print(res)

四、ORM查詢最佳化

​ ORM查詢最佳化是指,在我們使用的ORM語句進行查詢時,它的底層幫助我們做了很多的最佳化,其目的都是為了節省記憶體空間

  • ORM預設都是惰性查詢

    • 當我們不執行列印操作的時候,ORM語句不會執行,想要看到這個現象需要開啟日誌功能,即在配置檔案中進行配置
  • ORM查詢自帶分頁

    • 可以透過日誌展示的程式碼檢視,日誌返回的sql程式碼後端會有一個limit
  • only與defer

    • 特別說明

1、only與defer

前置說明

​ 這裡需要做一些具體的說明,方便大家理解only和defer。

​ 當我們在Django中執行ORM操作進行資料庫查詢的時候,其實內部的程式碼把所有的資料庫中的記錄,都封裝到了ORM操作的物件中去了,因此我們可以透過點的方式或是索引等方式查詢到對應的資料。

​ 但是當遇到查詢的時候需要查詢不在條件中的記錄時,就需要執行sql語句進行查詢了。

​ 比如我們在查詢的時候,需要的結果在外來鍵對應的表中,這時候去外來鍵對應的表中查詢資料,就需要執行sql語句進行查詢,並且查詢一條記錄需要執行一次sql語句

​ 而我們的only的作用是把寫在括號內的引數中的欄位的值封裝到物件中,讓後續查詢的時候 不需要執行sql語句進行查詢,加快執行速度。或是起到一個減少程式碼封裝的資料量,加快執行的作用。

​ 而defer則是和only相反,寫在括號內的欄位值不會被封裝到物件中,別的欄位反而會被封裝到物件中。

only

​ 獲取資料物件+含有指定欄位對應的資料

res = models.Book.objects.only('title', 'price')
print(res)  # queryset [資料物件、資料物件]
for obj in res:
    print(obj.title)  # 點選括號內填寫的欄位 不走SQL查詢
    print(obj.price)
    print(obj.publish_time)  # 可以點選括號內沒有的欄位獲取資料 但是會走SQL查詢

defer

res = models.Book.objects.defer('title', 'price')
print(res)  # queryset [資料物件、資料物件]
for obj in res:
    print(obj.title)  # 點選括號內填寫的欄位 走SQL查詢
    print(obj.price)
    print(obj.publish_time)  # 點選括號內沒有的欄位獲取資料 不走SQL查詢

五、ORM事務操作

事務的四大特性(ACID)

​ 原子性、一致性、隔離性、永續性

相關SQL關鍵字

1、開啟事務
    start transaction;
2、回滾
    rollback;
3、提交
    commit;
4、設定回滾節點
    savepoint;

相關重要概念

​ 髒讀、幻讀、不可重複讀、MVCC多版本控制...

1、Django開啟事務的方法

方法一:全域性有效

# 配置檔案的資料庫相關配置中新增鍵值對	
	"ATOMIC_REQUESTS": True

方法二:裝飾器

# 區域性有效,這個檢視函式內的一些orm操作屬於一個事務
     from django.db import transaction
        @transaction.atomic
        def index():pass

方法三:上下文管理

# 區域性有效,寫在with下方的orm操作屬於一個事務
    from django.db import transaction
    def reg():
        with transaction.atomic():
            pass

注意事項

​ 這裡的三種方法有個小區別,前面兩種方式執行事務,檢視層函式遇到返回值型別不對,orm操作可以正常執行的,但是with上下文管理的方式操作事務的話,則不行,操作會回退。

六、ORM常用欄位型別

1、預設欄位型別

名稱 含義
AutoField() Int自增列 必須填入引數 primary_key=True 當model中如果沒有自增列 則自動會建立一個列名為id的列
CharField() 字元型別 必須提供max_length引數 max_length表示字元長度
IntegerField() 一個整數型別 範圍在 -2147483648 to 2147483647 (一般不用它來存手機號(位數也不夠) 直接用字串存)
BigIntegerField() 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807
DateField() 日期欄位 日期格式 YYYY-MM-DD 相當於Python中的datetime.date()例項
DateTimeField() 日期時間欄位 格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] 相當於Python中的datetime.datetime()例項
DecimalField() 10進位制小數 引數 max_digits 小數總長度 decimal_places,小數位長度
EmailField() 字串型別 Django Admin以及ModelForm中提供驗證機制
BooleanField() 布林值型別 傳佈爾值存數字0或1
TextField() 文字型別 儲存大段文字
FileField() 字串 路徑儲存在資料庫 檔案上傳到指定目錄
引數 upload_to = " " 上傳檔案的儲存路徑
storage = None 儲存元件 預設django.core.files.storage.FileSystemStorage
ForeignKey() 外來鍵型別在ORM中用來表示外來鍵關聯關係 一般把ForeignKey欄位設定在 '一對多’中’多’的一方 ForeignKey可以和其他表做關聯關係同時也可以和自身做關聯關係
OneToOneField() 一對一欄位 通常一對一欄位用來擴充套件已有欄位 通俗的說就是一個人的所有資訊不是放在一張表裡面的,簡單的資訊一張表,隱私的資訊另一張表,之間透過一對一外來鍵關聯
ManyToManyField() 簡單來說就是在多對多表關係並且這一張多對多的關係表是有Django自動幫你建的情況下 下面的方法才可使用create add set remove clear

2、自定義欄位型別

​ ORM支援使用者自定義欄位型別,比方說ORM中沒有設定char型別的欄位,我們可以使用自定義欄位來實現他。

方法

class MyCharField(models.Field):
    def __init__(self, max_length, *args, **kwargs):
		self.max_length = max_length
		uper().__init__(max_length=max_length, *args, **kwargs)

	def db_type(self, connection):
		return 'char(%s)' % self.max_length


# 這裡是呼叫我們定義的欄位型別
class User(models.Model):
    name = models.CharField(max_length=32)
    info = MyCharField(max_length=64)

image-20221219200441260

七、ORM常用欄位引數

名稱 含義
primary_key 主鍵
verbose_name 註釋
max_length 欄位長度
max_digits 小數總共多少位
decimal_places 小數點後面的位數
auto_now 每次運算元據自動更新事件
auto_now_add 首次建立自動更新事件後續不自動更新
null 允許欄位為空
default 欄位預設值
unique 唯一值
db_index 給欄位新增索引
choices 當某個欄位的可能效能夠被列舉完全的情況下使用。如:性別、學歷、工作狀態、...
to 關聯表
to_field 關聯欄位(不寫預設關聯資料主鍵)
on_delete 當刪除關聯表中的資料時,當前表與其關聯的行的行為。

on_delete

​ 當兩張連表進行關聯後,主表的資料被刪除時,從表中對應的資料正在預設情況下也會被刪除,但是on_delete可以設定預設值,當主表資料被刪除時,從表中對應的資料會被修改為預設值

def func():
    return 10

class MyModel(models.Model):
    user = models.ForeignKey(
                    to="User",
                    to_field="id",
                    on_delete=models.SET(func)
                    )   
 # on_delete可以設定預設值,當主表資料被刪除時,從表中對應的資料會被修改為預設值


不同值對應的功能:
1、models.CASCADE
	級聯操作,當主表中被連線的一條資料刪除時,從表中所有與之關聯的資料同時被刪除

2、models.SET_NULL
    當主表中的一行資料刪除時,從表中所有與之關聯的資料的相關欄位設定為null,此時注意定義外來鍵時,這個欄位必須可以允許為空
    
3、models.PROTECT
    當主表中的一行資料刪除時,由於從表中相關欄位是受保護的外來鍵,所以都不允許刪除
    
4、models.SET_DEFAULT
    當主表中的一行資料刪除時,從表中所有相關的資料的關聯欄位設定為預設值,此時注意定義外來鍵時,這個外來鍵欄位應該有一個預設值
    
5、models.SET()
    當主表中的一條資料刪除時,從表中所有的關聯資料欄位設定為SET()中設定的值,與models.SET_DEFAULT相似,只不過此時從表中的相關欄位不需要設定default引數
       
6、models.DO_NOTHING
    什麼都不做,一切都看資料庫級別的約束,注資料庫級別的預設約束為RESTRICT,這個約束與django中的models.PROTECT相似

choices

​ 當欄位資料的可能性是可以完全列舉出來的時候 應該考慮使用該引數

  • get_gender_display()
    • 獲取choices引數內的資料值
class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    gender_choice = (
        (1, '男性'),
        (2, '女性'),
        (3, 'other'),
    )
    gender = models.IntegerField(choices=gender_choice)

user_obj = models.UserInfo.objects.filter(pk=1).first()
print(user_obj.gender)  # 獲取的是真實資料
print(user_obj.get_gender_display())
user_obj1 = models.UserInfo.objects.filter(pk=2).first()
user_obj2 = models.UserInfo.objects.filter(pk=3).first()
user_obj3 = models.UserInfo.objects.filter(pk=4).first()
print(user_obj1.get_gender_display())
print(user_obj2.get_gender_display())
print(user_obj3.get_gender_display())   # 如果沒有則按照真實資料返回

image-20221219202307836

相關文章