Django 2.1.3 文件-模型層-QuerySet 方法參考
QuerySetAPI參考
– 譯自官方文件+自己的理解 –
本文件描述了QuerySetAPI 的詳細資訊。它建立在 模型 和 資料庫查詢 指南中提供的材料之上,因此在閱讀本文件之前,您可能希望閱讀並理解這些文件。
在整個參考文獻中,我們將使用資料庫查詢指南中提供的示例Weblog模型。
1.什麼時候QuerySet求值
本質上,QuerySet可以構造,過濾,切片,並且通常可以在不實際訪問資料庫的情況下傳遞。在您對queryset求值之前,實際上不會發生任何資料庫活動。
您可以通過以下方式對QuerySet求值 :
(1)迭代。一個QuerySet是可迭代的,並且在您第一次迭代它時執行其資料庫查詢。例如,這將列印資料庫中所有書籍的名稱:
for e in Book.objects.all():
print(e.name)
注意:如果您只想確定是否存在至少一個結果,請不要使用此選項。使用exists()
效率更高。
>>> Book.objects.exists()
True
(2)切片。如 限制查詢集 中所述,可以使用Python的陣列切片語法對QuerySet進行切片。切片未評估的 QuerySet通常會返回另一個未評估的值QuerySet,但如果使用切片語法的“step”引數,Django將執行資料庫查詢,並返回一個列表。QuerySet對已經過評估的切片也會返回一個列表。
還要注意,即使對未評估的QuerySet切片返回另一個未評估QuerySet,進一步修改它(例如,新增更多過濾器,或修改排序)是不允許的,因為這不能很好地轉換為SQL,它也沒有明確的含義。
(3)醃製/快取。有關醃製QuerySets時所涉及的內容的詳細資訊,請參閱以下部分。對於本節而言,重要的是從資料庫中讀取結果。
(4)repr()
。在QuerySet上呼叫repr()方法進行求值,這是為了方便Python互動式直譯器,因此您可以在互動式使用API時立即看到結果。
(5)len()
。在QuerySet上呼叫len()方法進行求值. 正如您所料,這會返回結果列表的長度。
注意:如果您只需要確定集合中的記錄數(並且不需要實際物件),那麼使用SQL處理資料庫級別的計數方法SELECT COUNT(*)
會更有效。Django 正是出於這個原因提供了一種count()
方法。
(6)list()
。在QuerySet上呼叫list()方法進行求值。
例子:
def fun05_queryset_api():
print(Book.objects.exists())
print(repr(Book.objects.all()))
print(len(Book.objects.all()))
print(Book.objects.all().count())
print(list(Book.objects.all()))
# 輸出結果
<QuerySet [<Book: <吶喊>>, <Book: <哈利波特>>, <Book: <滅亡>>, <Book: <中國文人集>>]>
4
4
[<Book: <吶喊>>, <Book: <哈利波特>>, <Book: <滅亡>>, <Book: <中國文人集>>]
(7)bool()
。測試QuerySet在布林上下文中,如使用 bool(),or,and或if語句,將導致查詢被執行。如果至少有一個結果,QuerySet則為 True,否則False。例如:
if Book.objects.filter(name__contains="吶"):
print("There is at least one Book with the name contains 吶")
注意:如果您只想確定是否存在至少一個結果(並且不需要實際物件),則使用exists()會更有效。
2. 醃製(pickling)QuerySets
如果醃製 (pickle) 一個QuerySet,這將強制所有結果在醃製之前載入到記憶體中。醃製通常用作快取的前身,並且當重新載入快取的查詢集時,您希望結果已經存在並且可以使用(從資料庫讀取可能需要一些時間,從而無法實現快取)。這意味著當你取消醃製(unpickle)QuerySet,它包含被醃製時的結果,而不是當前在資料庫中的結果。
如果您只想醃製必要的資訊以便QuerySet稍後從資料庫重新建立 ,請醃製該QuerySet的query屬性。然後,您可以使用以下程式碼重新建立原始的QuerySet(沒有載入任何結果):
>>> import pickle
>>> query = pickle.loads(s) # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query # Restore the original 'query'.
該query屬性是一個不透明的物件。它表示查詢構造的內部,不是公共API的一部分。但是,如此處所述,對屬性的內容進行pickle和unpickle是安全的(並且完全支援)。
您無法在版本之間共享pickles資料
醃製 QuerySets僅對用於生成它們的Django版本有效。如果使用Django版本N生成pickle,則無法保證使用Django版本N + 1可以讀取pickle。醃製資料不應該用作長期存檔的策略。
由於pickle相容性錯誤很難診斷,例如無提示損壞的物件,因此當您嘗試在Django版本中取消查詢不同於其被pickle的查詢集時,會引發RuntimeWarning錯誤。
3. QuerySet API
這是一個正式的QuerySet宣告:
class QuerySet(model = None,query = None,using = None)
原始碼
通常,當您與一個QuerySet進行互動時,您將通過 過濾器鏈 來使用它 。為了使其工作,大多數 QuerySet方法返回新的查詢集。本節稍後將詳細介紹這些方法。
該QuerySet 類有可用於內省的兩個公共屬性:
(1)ordered
如果QuerySet是有序的返回True - 即在模型上有一個order_by()子句或預設排序;否則返回False。
(2)db
現在執行此查詢時將使用的資料庫。
註解
QuerySet存在一個query引數,以便專門的查詢子類可以重建內部查詢狀態。引數的值是該查詢狀態的不透明表示,並且不是公共API的一部分。簡單地說:如果你需要問,你不需要使用它。
print(Book.objects.all().ordered)
print(Book.objects.order_by('name').ordered)
print(Book.objects.all().db)
print(Book.objects.all().query)
# 輸出結果
False
True
default
SELECT "filter_book"."id", "filter_book"."name", "filter_book"."price", "filter_book"."category", "filter_book"."publishs_id" FROM "filter_book"
3.1 返回新QuerySets的方法
Django提供了一系列QuerySet細化方法,可以修改由其返回QuerySet的結果型別或執行SQL查詢的方式。
filter()
filter(** kwargs)
返回一個QuerySet,包含與給定查詢引數匹配的所有物件。
查詢引數(**kwargs)
應採用下面的欄位查詢中描述的格式 。多個引數通過AND在底層SQL語句中連線起來。
如果需要執行更復雜的查詢(例如,帶OR語句的查詢),則可以使用Q 物件。
exclude()
exclude(** kwargs)
返回一個QuerySet,包含與給定查詢引數不匹配的所有物件。
查詢引數(**kwargs)應採用下面的欄位查詢中描述的格式 。多個引數通過AND在底層SQL語句中連線起來,整個事件都包含在一個NOT()中。
此示例排除所有價格小於30並且書名包含“吶喊”的書籍:
print(Book.objects.exclude(price__lt=30,name__contains="吶喊"))
# 輸出結果
<QuerySet [<Book: <哈利波特>>, <Book: <滅亡>>, <Book: <中國文人集>>]>
在SQL術語中,轉化為:
SELECT ...
WHERE
NOT ("filter_book"."name" LIKE '%吶喊%'
AND "filter_book"."price" < 30)
此示例排除所有價格小於30或者書名包含“吶喊”的書籍::
print(Book.objects.exclude(price__lt=30).exclude(name__contains="吶喊"))
# 輸出結果
<QuerySet [<Book: <哈利波特>>, <Book: <中國文人集>>]>
在SQL術語中,評估為:
SELECT ...
FROM "filter_book"
WHERE (NOT ("filter_book"."price" < 30)
AND
NOT ("filter_book"."name" LIKE '%吶喊%' )
請注意,第二個示例更具限制性。
如果需要執行更復雜的查詢(例如,帶OR語句的查詢),則可以使用Q 物件。
annotate()
annotate(* args,** kwargs)