本篇筆記為Django筆記系列之十二,首發於公號【Django筆記】
本篇筆記將介紹查詢中的 defer 和 only 兩個函式的用法,筆記目錄如下:
- defer
- 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指定返回欄位
如果想獲取更多相關文章,可掃碼關注閱讀: