Django QuerySet查詢集原理及代碼實(shí)例
一 概念
Django的ORM中存在查詢集的概念。
查詢集,也稱查詢結(jié)果集、QuerySet,表示從數(shù)據(jù)庫中獲取的對象集合。
當(dāng)調(diào)用如下過濾器方法時(shí),Django會返回查詢集(而不是簡單的列表):
- all():返回所有數(shù)據(jù)。
- filter():返回滿足條件的數(shù)據(jù)。
- exclude():返回滿足條件之外的數(shù)據(jù)。
- order_by():對結(jié)果進(jìn)行排序。
對查詢集可以再次調(diào)用過濾器進(jìn)行過濾,也就意味著查詢集可以含有零個(gè)、一個(gè)或多個(gè)過濾器。過濾器基于所給的參數(shù)限制查詢的結(jié)果。
從SQL的角度講,查詢集與select語句等價(jià),過濾器像where、limit、order by子句。
二 兩大特性
1)惰性執(zhí)行
創(chuàng)建查詢集不會訪問數(shù)據(jù)庫,直到調(diào)用數(shù)據(jù)時(shí),才會訪問數(shù)據(jù)庫,調(diào)用數(shù)據(jù)的情況包括迭代、序列化、與if合用
例如,當(dāng)執(zhí)行如下語句時(shí),并未進(jìn)行數(shù)據(jù)庫查詢,只是創(chuàng)建了一個(gè)查詢集qs
# 查詢BookInfo模型類中的所有數(shù)據(jù) qs = BookInfo.objects.all() # 繼續(xù)執(zhí)行遍歷迭代操作后,才真正的進(jìn)行了數(shù)據(jù)庫的查詢 for book in qs: print(book.btitle)
2)緩存
使用同一個(gè)查詢集,第一次使用時(shí)會發(fā)生數(shù)據(jù)庫的查詢,然后Django會把結(jié)果緩存下來,再次使用這個(gè)查詢集時(shí)會使用緩存的數(shù)據(jù),減少了數(shù)據(jù)庫的查詢次數(shù)。
情況一:如下是兩個(gè)查詢集,無法重用緩存,每次查詢都會與數(shù)據(jù)庫進(jìn)行一次交互,增加了數(shù)據(jù)庫的負(fù)載。
from booktest.models import BookInfo
# 每個(gè)列表內(nèi)都為一個(gè)獨(dú)立的查詢集,兩次查詢集之間如果有數(shù)據(jù)插入,可能數(shù)據(jù)集會不同
[book.id for book in BookInfo.objects.all()][book.id for book in BookInfo.objects.all()]
情況二:經(jīng)過存儲后,可以重用查詢集,第二次使用緩存中的數(shù)據(jù)。
# 首先獲得一個(gè)查詢集 qs=BookInfo.objects.all() # 第一次讀取數(shù)據(jù),會查詢數(shù)據(jù)庫,然后增加緩存 [book.id for book in qs] # 第二次讀取數(shù)據(jù),直接查詢緩存 [book.id for book in qs]
3)何時(shí)查詢集不會被緩存?
查詢集不會永遠(yuǎn)緩存它們的結(jié)果。當(dāng)只對查詢集的部分進(jìn)行求值時(shí)會檢查緩存, 如果這個(gè)部分不在緩存中,那么接下來查詢返回的記錄都將不會被緩存。所以,這意味著使用切片或索引來限制查詢集將不會填充緩存。
情況一:重復(fù)獲取查詢集對象中一個(gè)特定的索引將每次都查詢數(shù)據(jù)庫:
queryset = BookInfo.objects.all()
queryset[5] # 查詢數(shù)據(jù)庫
queryset[5] # 再一次查詢數(shù)據(jù)庫
情況二:如果已經(jīng)對全部查詢集求值過,則將檢查緩存:
# 獲取查詢集 queryset = BookInfo.objects.all() [entry for entry in queryset] # 查詢數(shù)據(jù)庫 print queryset[5] # 使用緩存 print queryset[5] # 使用緩存
情況三:下面是一些其它例子,它們會使得全部的查詢集被求值并填充到緩存中:
# 獲取查詢集 queryset = BookInfo.objects.all() [entry for entry in queryset] bool(queryset) entry in queryset list(queryset)
注:簡單地打印查詢集不會填充緩存?! ?/p>
queryResult=models.Article.objects.all()
print(queryResult) # 查詢數(shù)據(jù)庫
print(queryResult) # 查詢數(shù)據(jù)庫
三 限制查詢集
1)、可以對查詢集進(jìn)行取下標(biāo)或切片操作,等同于sql中的limit和offset子句。
注意:不支持負(fù)數(shù)索引。
對查詢集進(jìn)行切片后返回一個(gè)新的查詢集,不會立即執(zhí)行查詢。
如果獲取一個(gè)對象,直接使用[0],等同于[0:1].get(),但是如果沒有數(shù)據(jù),[0]引發(fā)IndexError異常,[0:1].get()如果沒有數(shù)據(jù)引發(fā)DoesNotExist異常。
示例:獲取第1、2項(xiàng),運(yùn)行查看。
qs = BookInfo.objects.all()[0:2]
2)、exists()方法:判斷某一個(gè)查詢集中是否有數(shù)據(jù):
簡單的使用if語句進(jìn)行判斷也會完全執(zhí)行整個(gè)queryset并且把數(shù)據(jù)放入cache,雖然你并不需要這些 數(shù)據(jù)!為了避免這個(gè),可以用exists()方法,判斷查詢集中是否有數(shù)據(jù),如果有則返回True,沒有則返回False。
if queryResult.exists():
#SELECT (1) AS "a" FROM "blog_article" LIMIT 1; args=()
print("exists...")
3)、terator()方法: 來獲取數(shù)據(jù),處理完數(shù)據(jù)就將其丟棄。
當(dāng)queryset非常巨大時(shí),cache會成為問題。
處理成千上萬的記錄時(shí),將它們一次裝入內(nèi)存是很浪費(fèi)的。更糟糕的是,巨大的queryset可能會鎖住系統(tǒng) 進(jìn)程,讓你的程序?yàn)l臨崩潰。要避免在遍歷數(shù)據(jù)的同時(shí)產(chǎn)生queryset cache,可以使用iterator()方法 來獲取數(shù)據(jù),處理完數(shù)據(jù)就將其丟棄。
objs = BookInfo.objects.all().iterator() # iterator()可以一次只從數(shù)據(jù)庫獲取少量數(shù)據(jù),這樣可以節(jié)省內(nèi)存 for obj in objs: print(obj.title) #BUT,再次遍歷沒有打印,因?yàn)榈饕呀?jīng)在上一次遍歷(next)到最后一次了,沒得遍歷了 for obj in objs: print(obj.title)
注:(1) 使用iterator()方法來防止生成cache,意味著遍歷同一個(gè)queryset時(shí)會重復(fù)執(zhí)行查詢。所以使 #用iterator()的時(shí)候要當(dāng)心,確保你的代碼在操作一個(gè)大的queryset時(shí)沒有重復(fù)執(zhí)行查詢。
(2) queryset的cache是用于減少程序?qū)?shù)據(jù)庫的查詢,在通常的使用下會保證只有在需要的時(shí)候才會查詢數(shù)據(jù)庫。 使用exists()和iterator()方法可以優(yōu)化程序?qū)?nèi)存的使用。不過,由于它們并不會生成queryset cache,可能 會造成額外的數(shù)據(jù)庫查詢。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- django queryset 去重 .distinct()說明
- Python的Django框架實(shí)現(xiàn)數(shù)據(jù)庫查詢(不返回QuerySet的方法)
- Django ValuesQuerySet轉(zhuǎn)json方式
- Django框架 querySet功能解析
- django 中QuerySet特性功能詳解
- python實(shí)現(xiàn)合并多個(gè)list及合并多個(gè)django QuerySet的方法示例
- 介紹Python的Django框架中的QuerySets
- Python的Django框架中的select_related函數(shù)對QuerySet 查詢的優(yōu)化
相關(guān)文章
如何使用Tkinter進(jìn)行窗口的管理與設(shè)置
Tkinter是Python的標(biāo)準(zhǔn)GUI庫,它實(shí)際是建立在Tk技術(shù)上的。在大多數(shù)Unix平臺以及Windows系統(tǒng)上都可用2021-06-06Python爬蟲自動化爬取b站實(shí)時(shí)彈幕實(shí)例方法
在本篇文章里小編給大家整理的是一篇關(guān)于Python爬蟲自動化爬取b站實(shí)時(shí)彈幕實(shí)例方法,有興趣的朋友們可以學(xué)習(xí)下。2021-01-01Python實(shí)現(xiàn)的Kmeans++算法實(shí)例
這篇文章主要介紹了Kmeans和kmeans++算法,講解了Kmeans算法的缺點(diǎn)和kmeans++算法的實(shí)現(xiàn)思路,以及Python和matlab中實(shí)現(xiàn)的Kmeans++算法,需要的朋友可以參考下2014-04-04python?tkinter實(shí)現(xiàn)彈窗的輸入輸出
這篇文章主要為大家詳細(xì)介紹了python?tkinter實(shí)現(xiàn)彈窗的輸入輸出,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02python使用post提交數(shù)據(jù)到遠(yuǎn)程url的方法
這篇文章主要介紹了python使用post提交數(shù)據(jù)到遠(yuǎn)程url的方法,涉及Python使用post傳遞數(shù)據(jù)的相關(guān)技巧,需要的朋友可以參考下2015-04-04一篇文章帶你學(xué)習(xí)Python3的高階函數(shù)
這篇文章主要為大家詳細(xì)介紹了Python3的高階函數(shù),主要介紹什么是高階函數(shù),高階函數(shù)的用法以及幾個(gè)常見的內(nèi)置的高階函數(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01python 從csv讀數(shù)據(jù)到mysql的實(shí)例
今天小編就為大家分享一篇python 從csv讀數(shù)據(jù)到mysql的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-06-06