Django QuerySet查詢集原理及代碼實(shí)例
一 概念
Django的ORM中存在查詢集的概念。
查詢集,也稱查詢結(jié)果集、QuerySet,表示從數(shù)據(jù)庫(kù)中獲取的對(duì)象集合。
當(dāng)調(diào)用如下過(guò)濾器方法時(shí),Django會(huì)返回查詢集(而不是簡(jiǎn)單的列表):
- all():返回所有數(shù)據(jù)。
- filter():返回滿足條件的數(shù)據(jù)。
- exclude():返回滿足條件之外的數(shù)據(jù)。
- order_by():對(duì)結(jié)果進(jìn)行排序。
對(duì)查詢集可以再次調(diào)用過(guò)濾器進(jìn)行過(guò)濾,也就意味著查詢集可以含有零個(gè)、一個(gè)或多個(gè)過(guò)濾器。過(guò)濾器基于所給的參數(shù)限制查詢的結(jié)果。
從SQL的角度講,查詢集與select語(yǔ)句等價(jià),過(guò)濾器像where、limit、order by子句。
二 兩大特性
1)惰性執(zhí)行
創(chuàng)建查詢集不會(huì)訪問(wèn)數(shù)據(jù)庫(kù),直到調(diào)用數(shù)據(jù)時(shí),才會(huì)訪問(wèn)數(shù)據(jù)庫(kù),調(diào)用數(shù)據(jù)的情況包括迭代、序列化、與if合用
例如,當(dāng)執(zhí)行如下語(yǔ)句時(shí),并未進(jìn)行數(shù)據(jù)庫(kù)查詢,只是創(chuàng)建了一個(gè)查詢集qs
# 查詢BookInfo模型類(lèi)中的所有數(shù)據(jù) qs = BookInfo.objects.all() # 繼續(xù)執(zhí)行遍歷迭代操作后,才真正的進(jìn)行了數(shù)據(jù)庫(kù)的查詢 for book in qs: print(book.btitle)
2)緩存
使用同一個(gè)查詢集,第一次使用時(shí)會(huì)發(fā)生數(shù)據(jù)庫(kù)的查詢,然后Django會(huì)把結(jié)果緩存下來(lái),再次使用這個(gè)查詢集時(shí)會(huì)使用緩存的數(shù)據(jù),減少了數(shù)據(jù)庫(kù)的查詢次數(shù)。
情況一:如下是兩個(gè)查詢集,無(wú)法重用緩存,每次查詢都會(huì)與數(shù)據(jù)庫(kù)進(jìn)行一次交互,增加了數(shù)據(jù)庫(kù)的負(fù)載。
from booktest.models import BookInfo
# 每個(gè)列表內(nèi)都為一個(gè)獨(dú)立的查詢集,兩次查詢集之間如果有數(shù)據(jù)插入,可能數(shù)據(jù)集會(huì)不同
[book.id for book in BookInfo.objects.all()][book.id for book in BookInfo.objects.all()]
情況二:經(jīng)過(guò)存儲(chǔ)后,可以重用查詢集,第二次使用緩存中的數(shù)據(jù)。
# 首先獲得一個(gè)查詢集 qs=BookInfo.objects.all() # 第一次讀取數(shù)據(jù),會(huì)查詢數(shù)據(jù)庫(kù),然后增加緩存 [book.id for book in qs] # 第二次讀取數(shù)據(jù),直接查詢緩存 [book.id for book in qs]
3)何時(shí)查詢集不會(huì)被緩存?
查詢集不會(huì)永遠(yuǎn)緩存它們的結(jié)果。當(dāng)只對(duì)查詢集的部分進(jìn)行求值時(shí)會(huì)檢查緩存, 如果這個(gè)部分不在緩存中,那么接下來(lái)查詢返回的記錄都將不會(huì)被緩存。所以,這意味著使用切片或索引來(lái)限制查詢集將不會(huì)填充緩存。
情況一:重復(fù)獲取查詢集對(duì)象中一個(gè)特定的索引將每次都查詢數(shù)據(jù)庫(kù):
queryset = BookInfo.objects.all()
queryset[5] # 查詢數(shù)據(jù)庫(kù)
queryset[5] # 再一次查詢數(shù)據(jù)庫(kù)
情況二:如果已經(jīng)對(duì)全部查詢集求值過(guò),則將檢查緩存:
# 獲取查詢集 queryset = BookInfo.objects.all() [entry for entry in queryset] # 查詢數(shù)據(jù)庫(kù) print queryset[5] # 使用緩存 print queryset[5] # 使用緩存
情況三:下面是一些其它例子,它們會(huì)使得全部的查詢集被求值并填充到緩存中:
# 獲取查詢集 queryset = BookInfo.objects.all() [entry for entry in queryset] bool(queryset) entry in queryset list(queryset)
注:簡(jiǎn)單地打印查詢集不會(huì)填充緩存。
queryResult=models.Article.objects.all()
print(queryResult) # 查詢數(shù)據(jù)庫(kù)
print(queryResult) # 查詢數(shù)據(jù)庫(kù)
三 限制查詢集
1)、可以對(duì)查詢集進(jìn)行取下標(biāo)或切片操作,等同于sql中的limit和offset子句。
注意:不支持負(fù)數(shù)索引。
對(duì)查詢集進(jìn)行切片后返回一個(gè)新的查詢集,不會(huì)立即執(zhí)行查詢。
如果獲取一個(gè)對(duì)象,直接使用[0],等同于[0:1].get(),但是如果沒(méi)有數(shù)據(jù),[0]引發(fā)IndexError異常,[0:1].get()如果沒(méi)有數(shù)據(jù)引發(fā)DoesNotExist異常。
示例:獲取第1、2項(xiàng),運(yùn)行查看。
qs = BookInfo.objects.all()[0:2]
2)、exists()方法:判斷某一個(gè)查詢集中是否有數(shù)據(jù):
簡(jiǎn)單的使用if語(yǔ)句進(jìn)行判斷也會(huì)完全執(zhí)行整個(gè)queryset并且把數(shù)據(jù)放入cache,雖然你并不需要這些 數(shù)據(jù)!為了避免這個(gè),可以用exists()方法,判斷查詢集中是否有數(shù)據(jù),如果有則返回True,沒(méi)有則返回False。
if queryResult.exists():
#SELECT (1) AS "a" FROM "blog_article" LIMIT 1; args=()
print("exists...")
3)、terator()方法: 來(lái)獲取數(shù)據(jù),處理完數(shù)據(jù)就將其丟棄。
當(dāng)queryset非常巨大時(shí),cache會(huì)成為問(wèn)題。
處理成千上萬(wàn)的記錄時(shí),將它們一次裝入內(nèi)存是很浪費(fèi)的。更糟糕的是,巨大的queryset可能會(huì)鎖住系統(tǒng) 進(jìn)程,讓你的程序?yàn)l臨崩潰。要避免在遍歷數(shù)據(jù)的同時(shí)產(chǎn)生queryset cache,可以使用iterator()方法 來(lái)獲取數(shù)據(jù),處理完數(shù)據(jù)就將其丟棄。
objs = BookInfo.objects.all().iterator() # iterator()可以一次只從數(shù)據(jù)庫(kù)獲取少量數(shù)據(jù),這樣可以節(jié)省內(nèi)存 for obj in objs: print(obj.title) #BUT,再次遍歷沒(méi)有打印,因?yàn)榈饕呀?jīng)在上一次遍歷(next)到最后一次了,沒(méi)得遍歷了 for obj in objs: print(obj.title)
注:(1) 使用iterator()方法來(lái)防止生成cache,意味著遍歷同一個(gè)queryset時(shí)會(huì)重復(fù)執(zhí)行查詢。所以使 #用iterator()的時(shí)候要當(dāng)心,確保你的代碼在操作一個(gè)大的queryset時(shí)沒(méi)有重復(fù)執(zhí)行查詢。
(2) queryset的cache是用于減少程序?qū)?shù)據(jù)庫(kù)的查詢,在通常的使用下會(huì)保證只有在需要的時(shí)候才會(huì)查詢數(shù)據(jù)庫(kù)。 使用exists()和iterator()方法可以優(yōu)化程序?qū)?nèi)存的使用。不過(guò),由于它們并不會(huì)生成queryset cache,可能 會(huì)造成額外的數(shù)據(jù)庫(kù)查詢。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- django queryset 去重 .distinct()說(shuō)明
- Python的Django框架實(shí)現(xiàn)數(shù)據(jù)庫(kù)查詢(不返回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ù)對(duì)QuerySet 查詢的優(yōu)化
相關(guān)文章
python妹子圖簡(jiǎn)單爬蟲(chóng)實(shí)例
這篇文章主要介紹了python妹子圖簡(jiǎn)單爬蟲(chóng),實(shí)例分析了Python爬蟲(chóng)程序所涉及的頁(yè)面源碼獲取、進(jìn)度顯示、正則匹配等技巧,需要的朋友可以參考下2015-07-07
Python全角與半角之間相互轉(zhuǎn)換的方法總結(jié)
全角與半角轉(zhuǎn)換在處理漢語(yǔ)語(yǔ)料中會(huì)經(jīng)常出現(xiàn),這里分別說(shuō)明漢字、數(shù)字、字母的unicode編碼范圍,下面這篇文章主要給大家介紹了關(guān)于Python全角與半角之間相互轉(zhuǎn)換的相關(guān)資料,需要的朋友可以參考下2022-03-03
解決PyCharm無(wú)法使用lxml庫(kù)的問(wèn)題(圖解)
這篇文章主要介紹了解決PyCharm無(wú)法使用lxml庫(kù)的問(wèn)題,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
selenium+python實(shí)現(xiàn)文件上傳操作的方法實(shí)例
文件上傳功能是我們?cè)谌粘i_(kāi)發(fā)中經(jīng)常會(huì)遇到的一個(gè)需求,下面這篇文章主要給大家介紹了關(guān)于selenium+python實(shí)現(xiàn)文件上傳操作的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-08-08
Python中第三方庫(kù)Requests庫(kù)的高級(jí)用法詳解
雖然Python的標(biāo)準(zhǔn)庫(kù)中urllib2模塊已經(jīng)包含了平常我們使用的大多數(shù)功能,但是它的API使用起來(lái)讓人實(shí)在感覺(jué)不好。它已經(jīng)不適合現(xiàn)在的時(shí)代,不適合現(xiàn)代的互聯(lián)網(wǎng)了。而Requests的誕生讓我們有了更好的選擇。本文就介紹了Python中第三方庫(kù)Requests庫(kù)的高級(jí)用法。2017-03-03
Celery+django+redis異步執(zhí)行任務(wù)的實(shí)現(xiàn)示例
本文主要介紹了Celery+django+redis異步執(zhí)行任務(wù)的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04
Windows下PyCharm配置Anaconda環(huán)境(超詳細(xì)教程)
這篇文章主要介紹了Windows下PyCharm配置Anaconda環(huán)境,本文給大家分享一篇超詳細(xì)教程,通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07

