Django筆記十二之defer、only指定返回欄位

2023-03-31 06:01:11

本篇筆記為Django筆記系列之十二,首發於公號【Django筆記】

本篇筆記將介紹查詢中的 defer 和 only 兩個函數的用法,筆記目錄如下:

  1. defer
  2. only

1、defer

defer 的英語單詞的意思是 延遲、推遲,我們可以通過將欄位作為引數傳入,可以達到在獲取資料的時候指定不獲取該欄位資料,常用於一些 textfield 欄位上。

假設我們有一個 TestModel,有一個欄位名為 text_field,欄位型別為 textfield,裡面存了大量字串資料.

那麼如果我們在獲取這個 model 資料的時候,只想要這個 model 的其他欄位資訊, text_field 欄位的內容我們在這一次用不上,那麼我們就可以通過 defer() 方法來指定不獲取該欄位內容。

因為對於這一類大容量資料,系統在從資料庫中 fetch 資料的時候會花費大量時間,而這部分不必要的時間我們是可以避免的。

TestModel.objects.defer("text_field")

上面的語句將 text_field 這個欄位名作為引數傳入 defer() 函數,系統返回資料的時候將不會返回他的欄位。

我們以 Blog 這個model為例對這個函數進行測試,我們獲取 Blog 的資料,但是指定不獲取 name 這個欄位的資料:

Blog.objects.defer("name")

我們可以列印一下這條命令執行的 SQL 語句:

Blog.objects.defer("name").query.__str__()
SELECT `blog_blog`.`id`, `blog_blog`.`tagline` FROM `blog_blog`

可以看到轉化的 SQL 語句沒有把我們指定的 name 欄位返回。

不獲取外來鍵關聯的某些欄位

如果我們通過 select_related 關聯了外來鍵資料,也可以指定不獲取外來鍵的某些欄位,比如:

Entry.objects.select_related("blog").defer("blog__name")

這樣,在獲取關聯的 blog 的資料的時候,就不會獲取 blog 的 name 欄位資料。

defer 多欄位

Entry.objects.defer('headline', 'body_text')

主鍵欄位不能defer

有一些欄位我們是 defer 也不會生效的,比如 model 的主鍵欄位 id。

Blog.objects.defer("id")

上面的操作,系統不會報錯,但是也不會生效。

關聯外來鍵資料,外來鍵資料不應該被 defer

假設我們通過 Entry 來關聯獲取 Blog 資料,那麼,關聯的外來鍵欄位 blog_id,則不應該被 defer(),否則會報錯。

# 下面的寫法會報錯
Entry.objects.select_related("blog").defer("blog_id")

存取被 defer 的欄位

假設我們在獲取 Blog 資料的時候,defer 了 name 欄位,那麼我們還可以存取 name 欄位嗎?

答案是可以的,不過因為我們在第一步的時候沒有獲取該欄位,所以存取該欄位的時候,系統會再次請求一遍資料庫。

blog = Blog.objects.defer("name").first()

"""
這個時候列印出 blog 的所有欄位是:
blog.__dict__
{'_state': <django.db.models.base.ModelState object at 0x7fb2de420668>, 'id': 1, 'tagline': 'asd'}
"""

print(blog.name) # 存取被 defer 的欄位,系統會再次請求資料庫

"""
這個時候再次列印出 blog.__dict__ 內容是:
{'_state': <django.db.models.base.ModelState object at 0x7fb2de420668>, 'id': 1, 'tagline': 'asd', 'name': 'hunter'}
"""

2、only

與 defer() 方法的作用相反,only() 的意思是隻獲取指定的欄位,比如:

Entry.objects.only("headline", "rating")

與之對應的 SQL 是:

SELECT `blog_entry`.`id`, `blog_entry`.`headline`, `blog_entry`.`rating` FROM `blog_entry`

同樣的,如果存取沒有指定的欄位,系統會再次查詢資料庫。

如果是多個 only 連用,那麼系統只有最後一個 only 的欄位會生效:

Entry.objects.only("headline", "rating").only("body_text")  # 只會獲取 body_text 欄位資料

作用效果跟 order_by() 一樣,後面的引數會覆蓋前面的。

defer 和 only 連用

我們可以嘗試一下 defer 和 only 的先後順序,欄位是否相同,前者的欄位覆蓋後者,以及後者的欄位覆蓋前者等情況,這裡不做展開了。

因為,一般人誰會把這個兩個函數一起用呢。。。。。。

以上就是本篇筆記所有內容,下一篇筆記將介紹 get_or_create,update_or_create 等方法。

本文首發於本人微信公眾號:Django筆記。

原文連結:Django筆記十二之defer、only指定返回欄位

如果想獲取更多相關文章,可掃碼關注閱讀: