查詢集API -- Django從入門到精通系列教程
該系列教程繫個人原創,並完整發布在個人官網劉江的部落格和教程
所有轉載本文者,需在頂部顯著位置註明原作者及www.liujiangblog.com官網地址。
本節將詳細介紹查詢集的API,它建立在下面的模型基礎上,與上一節的模型相同:
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def __str__(self): # __unicode__ on Python 2 return self.name class Author(models.Model): name = models.CharField(max_length=200) email = models.EmailField() def __str__(self): # __unicode__ on Python 2 return self.name class Entry(models.Model): blog = models.ForeignKey(Blog, on_delete=models.CASCADE) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() mod_date = models.DateField() authors = models.ManyToManyField(Author) n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField() def __str__(self): # __unicode__ on Python 2 return self.headline
一、QuerySet何時被提交
在內部,建立、過濾、切片和傳遞一個QuerySet不會真實操作資料庫,在你對查詢集提交之前,不會發生任何實際的資料庫操作。
可以使用下列方法對QuerySet提交查詢操作:
- 迭代
QuerySet是可迭代的,在首次迭代查詢集時執行實際的資料庫查詢。 例如, 下面的語句會將資料庫中所有Entry的headline打印出來:
for e in Entry.objects.all():
print(e.headline)
切片:如果使用切片的”step“引數,Django 將執行資料庫查詢並返回一個列表。
Pickling/快取
repr()
len()
list():對QuerySet呼叫list()將強制提交操作
entry_list = list(Entry.objects.all())
bool()
測試布林值,像這樣:
if Entry.objects.filter(headline="Test"):
print("There is at least one Entry with the headline Test")
注:如果你需要知道是否存在至少一條記錄(而不需要真實的物件),使用exists() 將更加高效。
二、QuerySet
下面是對於QuerySet的正式定義:
class QuerySet(model=None, query=None, using=None)[source]
QuerySet類具有兩個公有屬性用於內省:
ordered:如果QuerySet是排好序的則為True,否則為False。
db:如果現在執行,則返回使用的資料庫。
三、返回新QuerySets的API
以下的方法都將返回一個新的QuerySets。重點是加粗的幾個API,其它的使用場景很少。
方法名 | 解釋 |
---|---|
filter() | 過濾查詢物件。 |
exclude() | 排除滿足條件的物件 |
annotate() | 使用聚合函式 |
order_by() | 對查詢集進行排序 |
reverse() | 反向排序 |
distinct() | 對查詢集去重 |
values() | 返回包含物件具體值的字典的QuerySet |
values_list() | 與values()類似,只是返回的是元組而不是字典。 |
dates() | 根據日期獲取查詢集 |
datetimes() | 根據時間獲取查詢集 |
none() | 建立空的查詢集 |
all() | 獲取所有的物件 |
union() | 並集 |
intersection() | 交集 |
difference() | 差集 |
select_related() | 附帶查詢關聯物件 |
prefetch_related() |
預先查詢 |
extra() | 附加SQL查詢 |
defer() | 不載入指定欄位 |
only() | 只加載指定的欄位 |
using() | 選擇資料庫 |
select_for_update() |
鎖住選擇的物件,直到事務結束。 |
raw() | 接收一個原始的SQL查詢 |
1. filter()
filter(**kwargs)
返回滿足查詢引數的物件集合。
查詢的引數(**kwargs)應該滿足下文欄位查詢中的格式。多個引數之間是和AND的關係。
2. exclude()
exclude(**kwargs)
返回一個新的QuerySet,它包含不滿足給定的查詢引數的物件。
查詢的引數(**kwargs)應該滿足下文欄位查詢中的格式。多個引數通過AND連線,然後所有的內容放入NOT() 中。
下面的示例排除所有pub_date
晚於2005-1-3且headline為“Hello” 的記錄:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
下面的示例排除所有pub_date
晚於2005-1-3或者headline 為“Hello” 的記錄:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
3. annotate()
annotate(*args, **kwargs)
使用提供的聚合表示式查詢物件。
表示式可以是簡單的值、對模型(或任何關聯模型)上的欄位的引用或者聚合表示式(平均值、總和等)。
annotate()的每個引數都是一個annotation,它將新增到返回的QuerySet每個物件中。
關鍵字引數指定的Annotation將使用關鍵字作為Annotation 的別名。 匿名引數的別名將基於聚合函式的名稱和模型的欄位生成。 只有引用單個欄位的聚合表示式才可以使用匿名引數。 其它所有形式都必須用關鍵字引數。
例如,如果正在操作一個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__count
42
Blog模型本身沒有定義entry__count
屬性,但是通過使用一個關鍵字引數來指定聚合函式,可以控制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_entries
42
4. order_by()
order_by(*fields)
預設情況下,根據模型的Meta類中的ordering屬性對QuerySet中的物件進行排序
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
上面的結果將按照pub_date
降序排序,然後再按照headline升序排序。"-pub_date"前面的負號表示降序順序。 升序是預設的。 要隨機排序,使用"?",如下所示:
Entry.objects.order_by('?')
注:order_by('?')
可能耗費資源且很慢,這取決於使用的資料庫。
若要按照另外一個模型中的欄位排序,可以使用查詢關聯模型的語法。即通過欄位的名稱後面跟兩個下劃線(__
),再加上新模型中的欄位的名稱,直到希望連線的模型。 像這樣:
Entry.objects.order_by('blog__name', 'headline')
如果排序的欄位與另外一個模型關聯,Django將使用關聯的模型的預設排序,或者如果沒有指定Meta.ordering將通過關聯的模型的主鍵排序。 例如,因為Blog模型沒有指定預設的排序:
Entry.objects.order_by('blog')
與以下相同:
Entry.objects.order_by('blog__id')
如果Blog設定了ordering = ['name']
,那麼第一個QuerySet將等同於:
Entry.objects.order_by('blog__name')
還可以通過呼叫表示式的desc()或者asc()方法:
Entry.objects.order_by(Coalesce('summary', 'headline').desc())
考慮下面的情況,指定一個多值欄位來排序(例如,一個ManyToManyField 欄位或者ForeignKey 欄位的反向關聯):
class Event(Model):
parent = models.ForeignKey(
'self',
on_delete=models.CASCADE,
related_name='children',
)
date = models.DateField()
Event.objects.order_by('children__date')
在這裡,每個Event可能有多個排序資料;具有多個children的每個Event將被多次返回到order_by()
建立的新的QuerySet中。 換句話說,用order_by()
方法對QuerySet物件進行操作會返回一個擴大版的新QuerySet物件。因此,使用多值欄位對結果進行排序時要格外小心。
沒有方法指定排序是否考慮大小寫。 對於大小寫的敏感性,Django將根據資料庫中的排序方式排序結果。
可以通過Lower將一個欄位轉換為小寫來排序,它將達到大小寫一致的排序:
Entry.objects.order_by(Lower('headline').desc())
可以通過檢查QuerySet.ordered
屬性來知道查詢是否是排序的。
每個order_by()
都將清除前面的任何排序。 例如下面的查詢將按照pub_date
排序,而不是headline:
Entry.objects.order_by('headline').order_by('pub_date')
5. reverse()
reverse()
反向排序QuerySet中返回的元素。 第二次呼叫reverse()將恢復到原有的排序。
如要獲取QuerySet中最後五個元素,可以這樣做:
my_queryset.reverse()[:5]
這與Python直接使用負索引有點不一樣。 Django不支援負索引,只能曲線救國。
6. distinct()
distinct(*fields)
去除查詢結果中重複的行。
預設情況下,QuerySet不會去除重複的行。當查詢跨越多張表的資料時,QuerySet可能得到重複的結果,這時候可以使用distinct()進行去重。
7. values()
values(*fields, **expressions)
返回一個包含資料的字典的queryset,而不是模型例項。
每個字典表示一個物件,鍵對應於模型物件的屬性名稱。
下面的例子將values() 與普通的模型物件進行比較:
# 列表中包含的是Blog物件
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>
# 列表中包含的是資料字典
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
該方法接收可選的位置引數*fields
,它指定values()應該限制哪些欄位。如果指定欄位,每個字典將只包含指定的欄位的鍵/值。如果沒有指定欄位,每個字典將包含資料庫表中所有欄位的鍵和值。
例如:
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
values()方法還有關鍵字引數**expressions
,這些引數將傳遞給annotate()
:
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower('name'))
<QuerySet [{'lower_name': 'beatles blog'}]>
在values()子句中的聚合應用於相同values()子句中的其他引數之前。 如果需要按另一個值分組,請將其新增到較早的values()子句中。 像這樣:
>>> from django.db.models import Count
>>> Blog.objects.values('author', entries=Count('entry'))
<QuerySet [{'author': 1, 'entries': 20}, {'author': 1, 'entries': 13}]>
>>> Blog.objects.values('author').annotate(entries=Count('entry'))
<QuerySet [{'author': 1, 'entries': 33}]>
注意:
如果你有一個欄位foo是一個ForeignKey,預設的foo_id
引數返回的字典中將有一個叫做foo 的鍵,因為這是儲存實際值的那個隱藏的模型屬性的名稱。 當呼叫foo_id
並傳遞欄位的名稱,傳遞foo 或values()都可以,得到的結果是相同的。像這樣:
>>> Entry.objects.values()
<QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]>
>>> Entry.objects.values('blog')
<QuerySet [{'blog': 1}, ...]>
>>> Entry.objects.values('blog_id')
<QuerySet [{'blog_id': 1}, ...]>
當values()與distinct()一起使用時,注意排序可能影響最終的結果。
如果values()子句位於extra()呼叫之後,extra()中的select引數定義的欄位必須顯式包含在values()呼叫中。 values( 呼叫後面的extra( 呼叫將忽略選擇的額外的欄位。
在values()之後呼叫only()和defer()不太合理,所以將引發一個NotImplementedError。
可以通過ManyToManyField、ForeignKey 和 OneToOneFiel 屬性反向引用關聯的模型的欄位:
>>> Blog.objects.values('name', 'entry__headline')
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
8. values_list()
values_list(*fields, flat=False)
與values()類似,只是在迭代時返回的是元組而不是字典。每個元組包含傳遞給values_list()
呼叫的相應欄位或表示式的值,因此第一個專案是第一個欄位等。 像這樣:
>>> Entry.objects.values_list('id', 'headline')
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list('id', Lower('headline'))
<QuerySet [(1, 'first entry'), ...]>
如果只傳遞一個欄位,還可以傳遞flat引數。 如果為True,它表示返回的結果為單個值而不是元組。 如下所示:
>>> Entry.objects.values_list('id').order_by('id')
<QuerySet[(1,), (2,), (3,), ...]>
>>> Entry.objects.values_list('id', flat=True).order_by('id')
<QuerySet [1, 2, 3, ...]>
如果有多個欄位,傳遞flat將發生錯誤。
如果不傳遞任何值給values_list()
,它將返回模型中的所有欄位,以在模型中定義的順序。
常見的情況是獲取某個模型例項的特定欄位值。可以使用values_list()
,然後呼叫get():
>>> Entry.objects.values_list('headline', flat=True).get(pk=1)
'First entry'
values()
和values_list()
都用於特定情況下的優化:檢索資料子集,而無需建立模型例項。
注意通過ManyToManyField進行查詢時的行為:
>>> Author.objects.values_list('name', 'entry__headline')
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
('George Orwell', 'Why Socialists Do Not Believe in Fun'),
('George Orwell', 'In Defence of English Cooking'),
('Don Quixote', None)]>
類似地,當查詢反向外來鍵時,對於沒有任何作者的條目,返回None。
>>> Entry.objects.values_list('authors')
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>
9. dates()
dates(field, kind, order='ASC')
返回一個QuerySet,表示QuerySet內容中特定型別的所有可用日期的datetime.date
物件列表。
field引數是模型的DateField的名稱。 kind引數應為"year","month"或"day"。 結果列表中的每個datetime.date物件被擷取為給定的型別。
"year" 返回對應該field的所有不同年份值的列表。
"month"返回欄位的所有不同年/月值的列表。
"day"返回欄位的所有不同年/月/日值的列表。
order引數預設為'ASC',或者'DESC'。 它指定如何排序結果。
例子:
>>> 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)]
10. datetimes()
datetimes(field_name, kind, order='ASC', tzinfo=None)
返回QuerySet,為datetime.datetime物件的列表,表示QuerySet內容中特定種類的所有可用日期。
field_name
應為模型的DateTimeField的名稱。
kind引數應為"hour","minute","month","year","second"或"day"。
結果列表中的每個datetime.datetime物件被擷取到給定的型別。
order引數預設為'ASC',或者'DESC'。 它指定如何排序結果。
tzinfo引數定義在擷取之前將資料時間轉換到的時區。
11. none()
none()
呼叫none()將建立一個不返回任何物件的查詢集,並且在訪問結果時不會執行任何查詢。
例子:
>>> Entry.objects.none()
<QuerySet []>
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True
12. all()
all()
返回當前QuerySet(或QuerySet子類)的副本。通常用於獲取全部QuerySet物件。
13. union()
union(*other_qs, all=False)
Django中的新功能1.11。也就是集合中並集的概念!
使用SQL的UNION運算子組合兩個或更多個QuerySet的結果。例如:
>>> qs1.union(qs2, qs3)
預設情況下,UNION操作符僅選擇不同的值。 要允許重複值,請使用all=True引數。
14. intersection()
intersection(*other_qs)
Django中的新功能1.11。也就是集合中交集的概念!
使用SQL的INTERSECT運算子返回兩個或更多個QuerySet的共有元素。例如:
>>> qs1.intersection(qs2, qs3)
15. difference()
difference(*other_qs)
Django中的新功能1.11。也就是集合中差集的概念!
使用SQL的EXCEPT運算子只保留QuerySet中的元素,但不保留其他QuerySet中的元素。例如:
>>> qs1.difference(qs2, qs3)
16. select_related()
select_related(*fields)
沿著外來鍵關係查詢關聯的物件的資料。這會生成一個複雜的查詢並引起效能的損耗,但是在以後使用外來鍵關係時將不需要再次資料庫查詢。
下面的例子解釋了普通查詢和select_related()
查詢的區別。 下面是一個標準的查詢:
# 訪問資料庫。
e = Entry.objects.get(id=5)
# 再次訪問資料庫以得到關聯的Blog物件。
b = e.blog
下面是一個select_related
查詢:
# 訪問資料庫。
e = Entry.objects.select_related('blog').get(id=5)
# 不會訪問資料庫,因為e.blog已經在前面的查詢中獲得了。
b = e.blog
select_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(),下面的語句將為每次迴圈迭代生成一個數據庫查詢,以獲得每個entry關聯的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 models
class City(models.Model):
# ...
pass
class 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)
呼叫Book.objects.select_related('author__hometown').get(id=4)
將快取相關的Person 和相關的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 的欄位。 此時,可以使用關聯物件欄位的related_name
,而不要指定欄位的名稱。
17. prefetch_related()
prefetch_related(*lookups)
在單個批處理中自動檢索每個指定查詢的相關物件。
與select_related
類似,但是策略是完全不同的。
假設有這些模型:
from django.db import models
class 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 2
return "%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()
查詢資料庫,因此self.toppings.all()
將在Pizza Pizza.__str__()
中的每個專案的Toppings表上執行查詢。
可以使用prefetch_related
減少為只有兩個查詢:
>>> Pizza.objects.all().prefetch_related('toppings')
這意味著現在每次self.toppings.all()
被呼叫,不會再去資料庫查詢,而是在一個預取的QuerySet快取中查詢。
還可以使用正常連線語法來執行相關欄位的相關欄位。 假設在上面的例子中增加一個額外的模型:
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
關係,以將查詢數減少為2:
>>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')
18. 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,)))
19. defer()
defer(*fields)
在一些複雜的資料建模情況下,模型可能包含大量欄位,其中一些可能包含大尺寸資料(例如文字欄位),將它們轉換為Python物件需要花費很大的代價。
當最初獲取資料時不知道是否需要這些特定欄位的情況下,如果正在使用查詢集的結果,可以告訴Django不要從資料庫中檢索它們。
通過傳遞欄位名稱到defer()實現不載入:
Entry.objects.defer("headline", "body")
具有延遲載入欄位的查詢集仍將返回模型例項。
每個延遲欄位將在你訪問該欄位時從資料庫中檢索(每次只檢索一個,而不是一次檢索所有的延遲欄位)。
可以多次呼叫defer()。 每個呼叫都向延遲集新增新欄位:
# 延遲body和headline兩個欄位。
Entry.objects.defer("body").filter(rating=5).defer("headline")
欄位新增到延遲集的順序無關緊要。對已經延遲的欄位名稱再次defer()沒有問題(該欄位仍將被延遲)。
可以使用標準的雙下劃線符號來分隔關聯的欄位,從而載入關聯模型中的欄位:
Blog.objects.select_related().defer("entry__headline", "entry__body")
如果要清除延遲欄位集,將None作為引數傳遞到defer():
# 立即載入所有的欄位。
my_queryset.defer(None)
defer()方法(及其兄弟,only())僅適用於高階用例,它們提供了資料載入的優化方法。
20. only()
only(*fields)
only()方法與defer()相反。
如果有一個模型幾乎所有的欄位需要延遲,使用only()指定補充的欄位集可以使程式碼更簡單。
假設有一個包含欄位biography、age和name的模型。 以下兩個查詢集是相同的,就延遲欄位而言:
Person.objects.defer("age", "biography")
Person.objects.only("name")
每當你呼叫only()時,它將替換立即載入的欄位集。因此,對only()的連續呼叫的結果是隻有最後一次呼叫的欄位被考慮:
# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")
由於defer()以遞增方式動作(向延遲列表中新增欄位),因此你可以結合only()和defer()呼叫:
# 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")
當對具有延遲欄位的例項呼叫save()時,僅儲存載入的欄位。
21. using()
using(alias)
如果正在使用多個數據庫,這個方法用於指定在哪個資料庫上查詢QuerySet。方法的唯一引數是資料庫的別名,定義在DATABASES。
例如:
# queries the database with the 'default' alias.
>>> Entry.objects.all()
# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')
22. select_for_update()
select_for_update(nowait=False, skip_locked=False)
返回一個鎖住行直到事務結束的查詢集,如果資料庫支援,它將生成一個SELECT ... FOR UPDATE
語句。
例如:
entries = Entry.objects.select_for_update().filter(author=request.user)
所有匹配的行將被鎖定,直到事務結束。這意味著可以通過鎖防止資料被其它事務修改。
一般情況下如果其他事務鎖定了相關行,那麼本查詢將被阻塞,直到鎖被釋放。使用select_for_update(nowait=True)
將使查詢不阻塞。如果其它事務持有衝突的鎖,那麼查詢將引發DatabaseError
異常。也可以使用select_for_update(skip_locked=True)
忽略鎖定的行。nowait和skip_locked
是互斥的。
目前,postgresql,oracle和mysql資料庫後端支援select_for_update()
。但是,MySQL不支援nowait和skip_locked
引數。
23. raw()
raw(raw_query, params=None, translations=None)
接收一個原始的SQL查詢,執行它並返回一個django.db.models.query.RawQuerySet
例項。
這個RawQuerySet例項可以迭代,就像普通的QuerySet一樣。