在接下來四五篇筆記中,將介紹 model 查詢方法的各個細節,為我們的查詢操作提供各種便利,
本篇筆記將介紹惰性查找、filter、exclude、annotate等方法,目錄如下:
- 惰性查找
- filter
- exclude
- annotate
- alias
- order_by
1、惰性查找
前面我們在介紹 Django 增刪改查的時候,提到過他的惰性查找的規則,
也就是說普通的 filter 陳述句執行時,系統并不會去查詢資料庫,只有當我們真正使用里面的資料的時候,才會去查詢資料庫,
那么以下介紹幾種,使用的時候會查詢資料庫的情況:
迭代
一個 QuerySet 是可迭代的,而且僅會在第一次迭代的時候查詢資料庫:
for e in Entry.objects.all():
print(e.headline)
切片
需要注意的是,使用 python 里的切片語法不會訪問資料庫,比如:
Entry.objects.all()[:3]
但是,如果使用 step 語法則會訪問資料庫,比如以下陳述句:
Entry.objects.all()[:10:2]
len()
當我們使用 len() 函式去獲取一個 QuerySet 的長度時,會訪問資料庫,比如:
len(Entry.objects.all())
但是這種做法是不被推薦的,因為他會把 QuerySet 中的所有資料,都加載出來,然后計算長度,
如果想要獲取總數量,我們會使用另一個函式,.count(),這個我們后面會提到,
list()
這個操作會強制查詢資料庫,然后將一個 QuerySet 轉換成 python 里的 list,
entry_list = list(Entry.objects.all())
在一般情況下,是不推薦的,因為相對于 list 而言,QuerySet 可以執行的函式更多,
bool()
判斷是否存在資料:
if Entry.objects.filter(headline='hunter'):
print('exists')
但是,在Django 里一般也不推薦,因為有更高效的用法,那就是使用 .exists() 函式,這個在后面會詳細介紹,
2、filter()
filter 這個函式前面都有介紹,可以在其中添加符合篩選條件,也可以通過鏈式的形式來操作,
但是鏈式執行的用法是 and 邏輯,如果想要用 or 邏輯,可以使用 Q() 用法來連用,前面也簡單介紹過,
3、exclude()
這個函式與 filter() 函式功能相反,是排除符合條件的資料,
4、annotate()
annotate 這個單詞的意思是 注釋,在 Django 里的用法是,通過對資料進行處理,比如一個運算式,或者是通過外鍵引入一個新的資料欄位,或者是聚合出來一個結果(比如平均值,綜合等),會在每一潭訓傳的資料里面新增一個前面運算式的結果作為一個新的欄位回傳,
比如我們獲取 Blog 這個 model 的時候,Entry 作為它的外鍵關系,我們可以獲取關聯了某條 Blog 的 Entry 的數量,并且作為新的欄位添加到 Blog 里一起回傳,其操作如下:
q = Blog.objects.annotate(number_of_entries=Count('entry’))
q[0].number_of_entries
5、alias()
alias() 的用法和 annotate 一樣,都可以創建新的資料欄位,但與 annotate() 不一樣的是,其結果并不會作為一個欄位回傳,而是用于在使用的程序中做篩選,比如一個用法如下:
q = Blog.objects.alias(number_of_entries=Count('entry')).filter(number_of_entries__gt=1)
6、order_by()
對于 QuerySet 每次回傳的結果,如果 Meta 里有 ordering 引數,使用見上一篇 Meta 的使用筆記,那么資料就會按照 ordering 的引數對資料進行排序后回傳,
如果 Meta 里沒有設定該引數,那么資料則會在有主鍵 id 的情況下按照 id 的順序回傳,
當然,我們也可以使用 order_by() 這個函式來對每一次搜索的資料進行排序的重寫,
正序排序
比如我們想要對 Entry 這個 model 對于 pub_date 進行正序排序:
Entry.objects.filter(pub_date__year=2005).order_by('pub_date')
倒序排序
則可以在欄位名前面加個 - 負號來操作:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date')
多個欄位進行排序
比如 對 pub_date 倒序排序,對 headline 正序排序,則是:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
按照外鍵欄位排序
比如 Entry 這個 model 需要按照外鍵 Blog 的 name 欄位來排序,則通過外鍵欄位+雙下劃線+排序欄位來實作:
Entry.objects.order_by('blog__name')
如果我們在查詢 Entry 的時候直接根據外鍵欄位,也就是 blog 來排序,Django 會使用 Blog,也就是外鍵的默認排序(即在 Blog 的 model 的 Meta 里設定的 ordering 來排序),如果外鍵沒有定義默認排序,則會根據主鍵 id 來排序,
比如說,我們的 Blog model,如果沒有在 Meta 里設定默認的 ordering,那么,下面的陳述句:
Entry.objects.order_by('blog')
則會等價于:
Entry.objects.order_by('blog_id')
如果在 Blog 的 model 的 Meta 里有設定 ordering=['name'],那么則等價于:
Entry.objects.order_by('blog__name')
查詢運算式呼叫 asc() 或者 desc() 方法:
Entry.objects.order_by(Coalesce('summary', 'headline').desc())
asc() 和 desc() 有 nulls_first 和 nulls_last 來控制 null 如何被排序,是放在最開始還是最后面,
忽略大小寫排序
我們可以通過對欄位進行小寫處理來達到忽略大小寫排序的目的:
Entry.objects.order_by(Lower('headline').desc())
不排序
如果是不想對資料進行任何排序,則可以直接呼叫 order_by() 函式,不添加任何引數即可,
Entry.objects.order_by()
不支持鏈式處理
需要注意的是,不同于 filter() 函式的鏈式操作,order_by() 是不支持鏈式操作的,每添加一次 order_by(),前面的排序都會被后面的覆寫,
Entry.objects.order_by('headline').order_by('pub_date')
以上陳述句則僅會根據 pub_date 進行排序,headline 的排序則會被忽略,
這個功能如果要驗證,很簡答,只需要列印出上述陳述句轉換成的 SQL 陳述句即可,
如果查看 Django 的 QuerySet 轉換的 SQL 代碼,以前寫過一篇博客,可以參考:https://blog.csdn.net/weixin_43354181/article/details/102881471
以上就是本篇筆記全部內容,接下來將要介紹的是 reverse、distinct、values、values_list 等用法,
本文首發于本人微信公眾號:Django筆記,
原文鏈接:Django筆記九之model查詢filter、exclude、annotate、order_by
如果想獲取更多相關文章,可掃碼關注閱讀:
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/548319.html
標籤:Python