【Python Django2.0入门教程】ORM之QuerySet 数据查询API:all get filter distinct first last count
在ORM增刪改操作文章里,主要講了ORM的增刪改查的基本操作,這節(jié)我們主要是講ORM查詢操作,查詢操作是Django的ORM框架中最重要的內(nèi)容之一,下面是我們常用到的與查詢相關(guān)的API。
注意,本章節(jié)的例子都是在上節(jié)的modesl.py基礎上做的。
<1>all(): 查詢所有結(jié)果 <2>filter(**kwargs) 它包含了與所給篩選條件相匹配的對象 <3>get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結(jié)果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。 <4>exclude(**kwargs) 它包含了與所給篩選條件不匹配的對象 <5>values(*field) 返回一個ValueQuerySet 一個特殊的QuerySet,運行后得到的并不是一系列model的實例化對象,而是一個可迭代的字典序列 <6>values_list(*field) 它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列 <7>order_by(*field) 對查詢結(jié)果排序 <8>reverse() 對查詢結(jié)果反向排序 <9>distinct() 從返回結(jié)果中剔除重復紀錄 <10>count() 返回數(shù)據(jù)庫中匹配查詢(QuerySet)的對象數(shù)量。 <11>first() 返回第一條記錄 <12>last() 返回最后一條記錄 <13>exists() 如果QuerySet包含數(shù)據(jù),就返回True,否則返回False <14>annotate() 使用聚合函數(shù) <15>dates() 根據(jù)日期獲取查詢集 <16>datetimes() 根據(jù)時間獲取查詢集 <17>none() 創(chuàng)建空的查詢集 <18>union() 并集 <19>intersection() 交集 <21>difference() 差集 <22>select_related() 附帶查詢關(guān)聯(lián)對象 <23>prefetch_related() 預先查詢 <24>extra() 附加SQL查詢 <25>defer() 不加載指定字段 <26>only() 只加載指定的字段 <27>using() 選擇數(shù)據(jù)庫 <28>select_for_update() 鎖住選擇的對象,直到事務結(jié)束。 <29>raw() 接收一個原始的SQL查詢注意:一定要區(qū)分出object與querySet的區(qū)別 !!!
1、檢索所有對象all()
使用all()方法,可以獲取某張表的所有記錄。返回當前QuerySet(或QuerySet子類)的副本。通常用于獲取全部QuerySet對象。
def orm(requst):#獲取所有文章,對應SQL:select * from Articleall_article = models.Article.objects.all()print(all_article)return HttpResponse('orm')保存之后,我們通過瀏覽器訪問,然后查看 Terminal,看到我們的打印出來的查詢結(jié)果,一共有四篇文章。
查詢出來的是一個QuerySet的對象。
2、用filter過濾對象
filter(**kwargs)
返回滿足查詢參數(shù)的對象集合。
查找的參數(shù)(**kwargs)應該滿足下文字段查找中的格式。多個參數(shù)之間是和AND的關(guān)系。
常用例子:
# 大于,>,對應SQL:select * from Article where id > 724 Article.objects.filter(id__gt=724) # 大于等于,>=,對應SQL:select * from Article where id >= 724 Article.objects.filter(id__gte=724) # 小于,<,對應SQL:select * from Article where id < 724 Article.objects.filter(id__lt=724) # 小于等于,<=,對應SQL:select * from Article where id <= 724 Article.objects.filter(id__lte=724) # 同時大于和小于, 1 < id < 10,對應SQL:select * from Article where id > 1 and id < 10 Article.objects.filter(id__gt=1, id__lt=10) # 包含,in,對應SQL:select * from Article where id in (11,22,33) Article.objects.filter(id__in=[11, 22, 33]) # 不包含,not in,對應SQL:select * from Article where id not in (11,22,33) Article.objects.filter(pub_date__isnull=True) # 不為空:isnull=False,對應SQL:select * from Article where pub_date is not null Article.objects.filter(pub_date__isnull=True) # 匹配,like,大小寫敏感,對應SQL:select * from Article where name like '%sre%',SQL中大小寫不敏感 Article.objects.filter(name__contains="sre") # 匹配,like,大小寫不敏感,對應SQL:select * from Article where name like '%sre%',SQL中大小寫不敏感 Article.objects.filter(name__icontains="sre") # 范圍,between and,對應SQL:select * from Article where id between 3 and 8 Article.objects.filter(id__range=[3, 8]) # 以什么開頭,大小寫敏感,對應SQL:select * from Article where name like 'sh%',SQL中大小寫不敏感 Article.objects.filter(name__startswith='sre') # 以什么開頭,大小寫不敏感,對應SQL:select * from Article where name like 'sh%',SQL中大小寫不敏感 Article.objects.filter(name__istartswith='sre') # 以什么結(jié)尾,大小寫敏感,對應SQL:select * from Article where name like '%sre',SQL中大小寫不敏感 Article.objects.filter(name__endswith='sre') # 以什么結(jié)尾,大小寫不敏感,對應SQL:select * from Article where name like '%sre',SQL中大小寫不敏感 Article.objects.filter(name__iendswith='sre') # 排序,order by,正序,對應SQL:select * from Article where name = '關(guān)鍵詞' order by id Article.objects.filter(name='關(guān)鍵詞').order_by('id') # 多級排序,order by,先按name進行正序排列,如果name一致則再按照id倒敘排列 Article.objects.filter(name='關(guān)鍵詞').order_by('name','-id') # 排序,order by,倒序,對應SQL:select * from Article where name = '關(guān)鍵詞' order by id desc Article.objects.filter(name='關(guān)鍵詞').order_by('-id')3、查詢單一對象 get
filter方法始終返回的是QuerySets,那怕只有一個對象符合過濾條件,返回的也是包含一個對象的QuerySets,這是一個集合類型對象,你可以簡單的理解為Python列表,可迭代可循環(huán)可索引。
如果你確定你的檢索只會獲得一個對象,那么你可以使用get()方法來直接返回這個對象。get返回與所給篩選條件相匹配的對象,返回結(jié)果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
4、查詢不匹配條件的對象 exclude
exclude(**kwargs)
返回一個新的QuerySet,它包含不滿足給定的查找參數(shù)的對象。
查找的參數(shù)(**kwargs)應該滿足下文字段查找中的格式。多個參數(shù)通過AND連接,然后所有的內(nèi)容放入NOT() 中。
下面的示例排除所有created_time晚于2018-7-15且headline為“Hello” 的記錄:
Article.objects.exclude(created_time__gt=datetime.date(2018,7,15), headline='Hello')下面的示例排除所有pub_date晚于2005-1-3或者headline 為“Hello” 的記錄:
Article.objects.exclude(created_time__gt=datetime.date(2018,7,15)).exclude(headline='Hello')5、查詢返回一個字典 values
返回一個ValueQuerySet,一個特殊的QuerySet,運行后得到的并不是一系列model的實例化對象,而是一個可迭代的字典序列。每個字典表示一個對象,鍵對應于模型對象的屬性名稱。
例:
#values()與普通的模型對象比較: def orm(requst):article = models.Article.objects.filter(title__startswith='增加')article_values = models.Article.objects.filter(title__startswith='增加').values()print(article)print('----------------------------------------------')print(article_values)return HttpResponse('orm')#打印結(jié)果 <QuerySet [<Article: 增加標題一>, <Article: 增加標題二>]> ---------------------------------------------- <QuerySet [ {'id': 4, 'title': '增加標題一', 'intro': '', 'category_id': 3, 'body': '增加內(nèi)容一', 'user_id': 1}, {'id': 6, 'title': '增加標題二', 'intro': '測試增加標題二', 'category_id': 4, 'body': '增加內(nèi)容二', 'user_id': 2}]>#更多用法: #不指定字段會獲取所有字段的鍵和值 article_values_all = models.Article.objects.values() #如果指定字段,每個字典將只包含指定的字段的鍵/值。 article_values_filter = models.Article.objects.values('id', 'title')#values()方法還有關(guān)鍵字參數(shù)**expressions,這些參數(shù)將傳遞給annotate()注釋 from django.db.models.functions import Lower article_values=models.Article.objects.values(標題=Lower('title')) <QuerySet [{'標題': '增加標題一'}, {'標題': '我被修改了'}, {'標題': '增加標題二'}]>#聚合應用,統(tǒng)計作者下的文章數(shù)量 from django.db.models import Count article_values_annotate = models.Article.objects.values('user').annotate(數(shù)量=Count('title')) <QuerySet [{'user': 1, '數(shù)量': 3}, {'user': 2, '數(shù)量': 2}]>#如果你有一個字段category是一個ForeignKey,默認的category_id參數(shù)返回的字典中將有一個叫做category的鍵, #因為這是保存實際值的那個隱藏的模型屬性的名稱 #當調(diào)用category_id并傳遞字段的名稱,傳遞category或values()都可以,得到的結(jié)果是相同的。 #像這樣: category=models.Article.objects.values('category') category_id = models.Article.objects.values('category_id') <QuerySet [{'category': 3}, {'category': 3}, {'category': 4}, {'category': 4}, {'category': 4}]> <QuerySet [{'category_id': 3}, {'category_id': 3}, {'category_id': 4}, {'category_id': 4}, {'category_id': 4}]>6、查詢返回一個元組 values_list
values_list(*fields, flat=False)
與values()類似,只是在迭代時返回的是元組而不是字典。每個元組包含傳遞給values_list()調(diào)用的相應字段或表達式的值,因此第一個項目是第一個字段等。
看例子:
from django.db.models.functions import Lower values_list=models.Article.objects.values_list('id','title') values_list_lower = models.Article.objects.values_list('id', Lower('title')) <QuerySet [(3, 'virtualenv使用技巧大全'), (4, '增加標題一'), (5, '我被修改了'), (6, '增加標題二')]> <QuerySet [(3, 'virtualenv使用技巧大全'), (4, '增加標題一'), (5, '我被修改了'), (6, '增加標題二')]>如果只傳遞一個字段,還可以傳遞flat參數(shù)。 如果為True,它表示返回的結(jié)果為單個值而不是元組。 如下所示:
values_list=models.Article.objects.values_list('id').order_by('id')values_list_flat = models.Article.objects.values_list('id', flat=True).order_by('id')<QuerySet [(2,), (3,), (4,), (5,), (6,)]><QuerySet [2, 3, 4, 5, 6]>如果有多個字段,傳遞flat將發(fā)生錯誤。
**7、查詢返回一個元組 order_by
**
order_by(*fields)
默認情況下,根據(jù)模型的Meta類中的ordering屬性對QuerySet中的對象進行排序
上面的結(jié)果將按照created_time降序排序,然后再按照title升序排序。"-created_time"前面的負號表示降序順序。 升序是默認的。 要隨機排序,使用"?",如下所示:
article = models.Article.objects.order_by('?')注:order_by(’?’)可能耗費資源且很慢,這取決于使用的數(shù)據(jù)庫。
若要按照另外一個模型中的字段排序,可以使用查詢關(guān)聯(lián)模型的語法。即通過字段的名稱后面跟兩個下劃線(__),再加上新模型中的字段的名稱,直到希望連接的模型。
article = models.Article.objects.order_by('category__name', 'title')如果排序的字段與另外一個模型關(guān)聯(lián),Django將使用關(guān)聯(lián)的模型的默認排序,或者如果沒有指定Meta.ordering將通過關(guān)聯(lián)的模型的主鍵排序。 例如,因為Blog模型沒有指定默認的排序:
article = models.Article.objects.order_by('category') #等于: article = models.Article.objects.order_by('category__id')如果Blog設置了ordering = [‘name’],那么第一個QuerySet將等同于:
article = models.Article.objects.order_by('category__name')還可以通過調(diào)用表達式的desc()或者asc()方法:
article = models.Article.objects.order_by(Coalesce('summary', 'title').desc())8、對查詢結(jié)果反向排序 reverse
反向排序QuerySet中返回的元素。 第二次調(diào)用reverse()將恢復到原有的排序。
如要獲取QuerySet中最后三個元素,可以這樣做:
這與Python直接使用負索引有點不一樣。 Django不支持負索引,只能曲線救國。
9、從返回結(jié)果中剔除重復紀錄 distinct
distinct(*fields)
去除查詢結(jié)果中重復的行。
默認情況下,QuerySet不會去除重復的行。當查詢跨越多張表的數(shù)據(jù)時,QuerySet可能得到重復的結(jié)果,這時候可以使用distinct()進行去重。
10、返回數(shù)據(jù)庫中匹配查詢(QuerySet)的對象數(shù)量 count
**返回一個整數(shù),該整數(shù)表示數(shù)據(jù)庫中與QuerySet匹配的對象的數(shù)量。
**
**例子:
**
#返回數(shù)據(jù)庫中的條目總數(shù)article = models.Article.objects.count()#返回標題中包含“增加”的條目數(shù)article_filter = models.Article.objects.filter(title__contains='增加').count()count()調(diào)用在幕后執(zhí)行SELECT count(*),因此您應該始終使用count(),而不是將所有記錄加載到Python對象中,然后對結(jié)果調(diào)用len()(除非無論如何都需要將對象加載到內(nèi)存中,在這種情況下,len()會更快)。
注意,如果您想要查詢一個QuerySet中的項目數(shù)量,并且正在從它檢索模型實例(例如,通過遍歷它),那么使用len(QuerySet)可能會更高效,因為它不會像count()那樣導致額外的數(shù)據(jù)庫查詢。
11、返回由queryset匹配的第一個對象 first*()*
返回由queryset匹配的第一個對象,如果沒有匹配的對象,則返回None。如果QuerySet沒有定義任何排序,那么QuerySet將由主鍵自動排序。
例子:
p = models.Article.objects.order_by('title', 'created_time').first()#文章的'上一頁'就是通過這個實現(xiàn)的previous_blog = Article.objects.filter(created_time__gt=article_obj.created_time).first()注意,first()是一種簡潔的寫法,下面的代碼示例與上面的示例等價:
try: p = models.Article.objects.order_by('title', 'created_time')[0]except IndexError: p = None12、返回最后一條記錄last()
與first()類似,它是返回queryset中的最后一個對象。
#文章下一頁netx_blog = Article.objects.filter(created_time__lt=article_obj.created_time).last()1****3、返回最后一條記錄exists()
如果QuerySet包含數(shù)據(jù),就返回True,否則返回False —只判斷是否有記錄
如果 QuerySet 包含任何結(jié)果,則返回 True,否則返回 False。這盡可能以最簡單和最快的方式執(zhí)行查詢,但它確實執(zhí)行與普通 QuerySet 查詢幾乎相同的查詢。
exists() 對于與 QuerySet 中的對象成員資格以及 QuerySet 中的任何對象(特別是大型 QuerySet 的上下文)中存在的相關(guān)搜索都很有用。
查找具有唯一字段(例如 primary_key)的模型是否為 QuerySet 的成員的最有效方法是:
entry = Entry.objects.get(pk=123) if some_queryset.filter(pk=entry.pk).exists(): print("Entry contained in queryset")這將比以下要求更快,需要對整個查詢集進行評估和迭代:
if entry in some_queryset: print("Entry contained in QuerySet")查找查詢集是否包含任何項目:
if some_queryset.exists(): print("There is at least one object in some_queryset")這將比以下更快:
if some_queryset: print("There is at least one object in some_queryset")…但不是很大程度上(因此需要大量查詢來提高效率)。
14、使用提供的聚合表達式查詢對象annotate()
函數(shù)原型annotate(*args, **kwargs),返回QuerySet。
表達式可以是簡單的值、對模型(或任何關(guān)聯(lián)模型)上的字段的引用或者聚合表達式(平均值、總和等)。
annotate()的每個參數(shù)都是一個annotation,它將添加到返回的QuerySet每個對象中。
關(guān)鍵字參數(shù)指定的Annotation將使用關(guān)鍵字作為Annotation 的別名。 匿名參數(shù)的別名將基于聚合函數(shù)的名稱和模型的字段生成。 只有引用單個字段的聚合表達式才可以使用匿名參數(shù)。 其它所有形式都必須用關(guān)鍵字參數(shù)。
例如,如果正在操作一個Blog列表,你可能想知道每個Blog有多少Entry:
>>> from django.db.models import Count>>> q = Blog.objects.annotate(Count('entry'))# The name of the first blog>>> q[0].name'Blogasaurus'# The number of entries on the first blog>>> q[0].entry__count42Blog模型本身沒有定義entry__count屬性,但是通過使用一個關(guān)鍵字參數(shù)來指定聚合函數(shù),可以控制Annotation的名稱:
>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))# The number of entries on the first blog, using the name provided>>> q[0].number_of_entries3515、根據(jù)日期獲取查詢集dates()
dates(field, kind, order=‘ASC’)
返回一個QuerySet,表示QuerySet內(nèi)容中特定類型的所有可用日期的datetime.date對象列表。
field參數(shù)是模型的DateField的名稱。 kind參數(shù)應為"year",“month"或"day”。 結(jié)果列表中的每個datetime.date對象被截取為給定的類型。
“year” 返回對應該field的所有不同年份值的列表。
"month"返回字段的所有不同年/月值的列表。
"day"返回字段的所有不同年/月/日值的列表。
order參數(shù)默認為’ASC’,或者’DESC’。 它指定如何排序結(jié)果。
例子:
>>> Entry.objects.dates('pub_date', 'year') [datetime.date(2005, 1, 1)] >>> Entry.objects.dates('pub_date', 'month') [datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)] >>> Entry.objects.dates('pub_date', 'day') [datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)] >>> Entry.objects.dates('pub_date', 'day', order='DESC') [datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)] >>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day') [datetime.date(2005, 3, 20)]16、根據(jù)時間獲取查詢集datetimes()
datetimes(field_name, kind, order=‘ASC’, tzinfo=None)
返回QuerySet,為datetime.datetime對象的列表,表示QuerySet內(nèi)容中特定種類的所有可用日期。
field_name應為模型的DateTimeField的名稱。
kind參數(shù)應為"hour",“minute”,“month”,“year”,“second"或"day”。
結(jié)果列表中的每個datetime.datetime對象被截取到給定的類型。
order參數(shù)默認為’ASC’,或者’DESC’。 它指定如何排序結(jié)果。
tzinfo參數(shù)定義在截取之前將數(shù)據(jù)時間轉(zhuǎn)換到的時區(qū)。
17、 創(chuàng)建空的查詢集none()
調(diào)用none()將創(chuàng)建一個不返回任何對象的查詢集,并且在訪問結(jié)果時不會執(zhí)行任何查詢。
例子:
>>> Entry.objects.none()<QuerySet []>>>> from django.db.models.query import EmptyQuerySet>>> isinstance(Entry.objects.none(), EmptyQuerySet)True18、并集union()
union(*other_qs, all=False)
Django中的新功能1.11。也就是集合中并集的概念!
使用SQL的UNION運算符組合兩個或更多個QuerySet的結(jié)果。例如:
>>> qs1.union(qs2, qs3)默認情況下,UNION操作符僅選擇不同的值。 要允許重復值,請使用all=True參數(shù)。
19、交集intersection()
intersection(*other_qs)
Django中的新功能1.11。也就是集合中交集的概念!
使用SQL的INTERSECT運算符返回兩個或更多個QuerySet的共有元素。例如:
>>> qs1.intersection(qs2, qs3)21、差集difference()
difference(*other_qs)
Django中的新功能1.11。也就是集合中差集的概念!
使用SQL的EXCEPT運算符只保留QuerySet中的元素,但不保留其他QuerySet中的元素。例如:
>>> qs1.difference(qs2, qs3)22、附帶查詢關(guān)聯(lián)對象select_related()
select_related(*fields)
沿著外鍵關(guān)系查詢關(guān)聯(lián)的對象的數(shù)據(jù)。這會生成一個復雜的查詢并引起性能的損耗,但是在以后使用外鍵關(guān)系時將不需要再次數(shù)據(jù)庫查詢。
下面的例子解釋了普通查詢和select_related()查詢的區(qū)別。 下面是一個標準的查詢:
# 訪問數(shù)據(jù)庫。e = Entry.objects.get(id=5)# 再次訪問數(shù)據(jù)庫以得到關(guān)聯(lián)的Blog對象。b = e.blog下面是一個select_related查詢:
# 訪問數(shù)據(jù)庫。e = Entry.objects.select_related('blog').get(id=5)# 不會訪問數(shù)據(jù)庫,因為e.blog已經(jīng)在前面的查詢中獲得了。b = e.blogselect_related()可用于objects任何的查詢集:
from django.utils import timezone# Find all the blogs with entries scheduled to be published in the future. blogs = set()for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog'):# 沒有select_related(),下面的語句將為每次循環(huán)迭代生成一個數(shù)據(jù)庫查詢,以獲得每個entry關(guān)聯(lián)的blog。blogs.add(e.blog)filter()和select_related()的順序不重要。 下面的查詢集是等同的:
Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog') Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())可以沿著外鍵查詢。 如果有以下模型:
from django.db import modelsclass City(models.Model):# ...passclass Person(models.Model):# ...hometown = models.ForeignKey(City,on_delete=models.SET_NULL,blank=True,null=True,)class Book(models.Model):# ...author = models.ForeignKey(Person, on_delete=models.CASCADE)調(diào)用Book.objects.select_related('author__hometown').get(id=4)將緩存相關(guān)的Person 和相關(guān)的City:
b = Book.objects.select_related('author__hometown').get(id=4) p = b.author # Doesn't hit the database. c = p.hometown # Doesn't hit the database. b = Book.objects.get(id=4) # No select_related() in this example. p = b.author # Hits the database. c = p.hometown # Hits the database.在傳遞給select_related()的字段中,可以使用任何ForeignKey和OneToOneField。
在傳遞給select_related的字段中,還可以反向引用OneToOneField。也就是說,可以回溯到定義OneToOneField 的字段。 此時,可以使用關(guān)聯(lián)對象字段的related_name,而不要指定字段的名稱。
23、預先查詢prefetch_related()
prefetch_related(*lookups)
在單個批處理中自動檢索每個指定查找的相關(guān)對象。
與select_related類似,但是策略是完全不同的。
假設有這些模型:
from django.db import modelsclass Topping(models.Model):name = models.CharField(max_length=30)class Pizza(models.Model):name = models.CharField(max_length=50)toppings = models.ManyToManyField(Topping)def __str__(self): # __unicode__ on Python 2return "%s (%s)" % (self.name,", ".join(topping.name for topping in self.toppings.all()),)并運行:
>>> Pizza.objects.all() ["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...問題是每次QuerySet要求Pizza.objects.all()查詢數(shù)據(jù)庫,因此self.toppings.all()將在Pizza Pizza.__str__()中的每個項目的Toppings表上運行查詢。
可以使用prefetch_related減少為只有兩個查詢:
>>> Pizza.objects.all().prefetch_related('toppings')這意味著現(xiàn)在每次self.toppings.all()被調(diào)用,不會再去數(shù)據(jù)庫查找,而是在一個預取的QuerySet緩存中查找。
還可以使用正常連接語法來執(zhí)行相關(guān)字段的相關(guān)字段。 假設在上面的例子中增加一個額外的模型:
class Restaurant(models.Model):pizzas = models.ManyToManyField(Pizza, related_name='restaurants')best_pizza = models.ForeignKey(Pizza, related_name='championed_by')以下是合法的:
>>> Restaurant.objects.prefetch_related('pizzas__toppings')這將預取所有屬于餐廳的比薩餅,和所有屬于那些比薩餅的配料。 這將導致總共3個查詢 - 一個用于餐館,一個用于比薩餅,一個用于配料。
>>> Restaurant.objects.prefetch_related('best_pizza__toppings')這將獲取最好的比薩餅和每個餐廳最好的披薩的所有配料。 這將在3個表中查詢 - 一個為餐廳,一個為“最佳比薩餅”,一個為一個為配料。
當然,也可以使用best_pizza來獲取select_related關(guān)系,以將查詢數(shù)減少為2:
>>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')24、附加SQL查詢extra()
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
有些情況下,Django的查詢語法難以簡單的表達復雜的WHERE子句,對于這種情況,可以在extra()生成的SQL從句中注入新子句。使用這種方法作為最后的手段,這是一個舊的API,在將來的某個時候可能被棄用。僅當無法使用其他查詢方法表達查詢時才使用它。
例如:
>>> qs.extra( ... select={'val': "select col from sometable where othercol = %s"}, ... select_params=(someparam,), ... )相當于:
>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))25、不加載指定字段defer()
defer(*fields)
在一些復雜的數(shù)據(jù)建模情況下,模型可能包含大量字段,其中一些可能包含大尺寸數(shù)據(jù)(例如文本字段),將它們轉(zhuǎn)換為Python對象需要花費很大的代價。
當最初獲取數(shù)據(jù)時不知道是否需要這些特定字段的情況下,如果正在使用查詢集的結(jié)果,可以告訴Django不要從數(shù)據(jù)庫中檢索它們。
通過傳遞字段名稱到defer()實現(xiàn)不加載:
Entry.objects.defer("headline", "body")具有延遲加載字段的查詢集仍將返回模型實例。
每個延遲字段將在你訪問該字段時從數(shù)據(jù)庫中檢索(每次只檢索一個,而不是一次檢索所有的延遲字段)。
可以多次調(diào)用defer()。 每個調(diào)用都向延遲集添加新字段:
# 延遲body和headline兩個字段。 Entry.objects.defer("body").filter(rating=5).defer("headline")字段添加到延遲集的順序無關(guān)緊要。對已經(jīng)延遲的字段名稱再次defer()沒有問題(該字段仍將被延遲)。
可以使用標準的雙下劃線符號來分隔關(guān)聯(lián)的字段,從而加載關(guān)聯(lián)模型中的字段:
Blog.objects.select_related().defer("entry__headline", "entry__body")如果要清除延遲字段集,將None作為參數(shù)傳遞到defer():
# 立即加載所有的字段。 my_queryset.defer(None)defer()方法(及其兄弟,only())僅適用于高級用例,它們提供了數(shù)據(jù)加載的優(yōu)化方法。
26、只加載指定的字段only()
only(*fields)
only()方法與defer()相反。
如果有一個模型幾乎所有的字段需要延遲,使用only()指定補充的字段集可以使代碼更簡單。
假設有一個包含字段biography、age和name的模型。 以下兩個查詢集是相同的,就延遲字段而言:
Person.objects.defer("age", "biography") Person.objects.only("name")每當你調(diào)用only()時,它將替換立即加載的字段集。因此,對only()的連續(xù)調(diào)用的結(jié)果是只有最后一次調(diào)用的字段被考慮:
# This will defer all fields except the headline. Entry.objects.only("body", "rating").only("headline")由于defer()以遞增方式動作(向延遲列表中添加字段),因此你可以結(jié)合only()和defer()調(diào)用:
# Final result is that everything except "headline" is deferred. Entry.objects.only("headline", "body").defer("body") # Final result loads headline and body immediately (only() replaces any # existing set of fields). Entry.objects.defer("body").only("headline", "body")當對具有延遲字段的實例調(diào)用save()時,僅保存加載的字段。
27、選擇數(shù)據(jù)庫using()
using(alias)
如果正在使用多個數(shù)據(jù)庫,這個方法用于指定在哪個數(shù)據(jù)庫上查詢QuerySet。方法的唯一參數(shù)是數(shù)據(jù)庫的別名,定義在DATABASES。
例如:
# queries the database with the 'default' alias. >>> Entry.objects.all() # queries the database with the 'backup' alias >>> Entry.objects.using('backup')28、鎖住選擇的對象,直到事務結(jié)束。select_for_update()
elect_for_update(nowait=False, skip_locked=False)
返回一個鎖住行直到事務結(jié)束的查詢集,如果數(shù)據(jù)庫支持,它將生成一個SELECT ... FOR UPDATE語句。
例如:
entries = Entry.objects.select_for_update().filter(author=request.user)所有匹配的行將被鎖定,直到事務結(jié)束。這意味著可以通過鎖防止數(shù)據(jù)被其它事務修改。
一般情況下如果其他事務鎖定了相關(guān)行,那么本查詢將被阻塞,直到鎖被釋放。使用select_for_update(nowait=True)將使查詢不阻塞。如果其它事務持有沖突的鎖,那么查詢將引發(fā)DatabaseError異常。也可以使用select_for_update(skip_locked=True)忽略鎖定的行。nowait和skip_locked是互斥的。
目前,postgresql,oracle和mysql數(shù)據(jù)庫后端支持select_for_update()。但是,MySQL不支持nowait和skip_locked參數(shù)。
29、接收一個原始的SQL查詢raw()
raw(raw_query, params=None, translations=None)
接收一個原始的SQL查詢,執(zhí)行它并返回一個django.db.models.query.RawQuerySet實例。
這個RawQuerySet實例可以迭代,就像普通的QuerySet一樣。
參考鏈接:https://www.django.cn/course/show-18.html
總結(jié)
以上是生活随笔為你收集整理的【Python Django2.0入门教程】ORM之QuerySet 数据查询API:all get filter distinct first last count的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: deepin 20.2.4 磁盘分区扩容
- 下一篇: 【Django博客开发教程】:数据查询