查詢集API -- Django從入門到精通系列教程

来源:https://www.cnblogs.com/feixuelove1009/archive/2018/02/06/8424607.html
-Advertisement-
Play Games

該系列教程系個人原創,並完整發佈在個人官網 "劉江的博客和教程" 所有轉載本文者,需在頂部顯著位置註明原作者及www.liujiangblog.com官網地址。 Python及Django學習QQ群:453131687 本節將詳細介紹查詢集的API,它建立在下麵的模型基礎上,與上一節的模型相同: 一 ...


該系列教程系個人原創,並完整發佈在個人官網劉江的博客和教程

所有轉載本文者,需在頂部顯著位置註明原作者及www.liujiangblog.com官網地址。

Python及Django學習QQ群:453131687


本節將詳細介紹查詢集的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():當你對QuerySet調用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-3headline為“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)

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,而不要指定欄位的名稱。

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一樣。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 引言   JDK中提供了自增運算符++,自減運算符 。這兩個操作符各有兩種使用方式:首碼式(++ a, a),尾碼式(a++,a )。可能說到這裡,說不得有讀者就會吐槽說,前尾碼式都挺簡單的,首碼式不就是先進行+1(或 1),然後再使用該值參與運算嘛,尾碼式則相反。有必要長篇大論 ...
  • 網上很多使用ecplise+phthon2.7中使用pytesser或者tesseract進行OCR網站驗證碼的案例,但配置起來實在讓人崩潰。 通用步驟:1、下載了pytesser_v0.0.1; 2、然後解壓後拷貝到C:\ProgramData\Anaconda2\Lib\site-package ...
  • JDK 安裝 下載安裝 下載JDK 從 "oracle官方網站" 下載並安裝JDK. 下載使用文檔 從 "oracle官方網站" 下載使用幫助文檔. 安裝庫源文件 源文件位於安裝目錄的 /Library/Java/JavaVirtualMachines/jdk 9.0.4.jdk/Contents/ ...
  • 【題目描述】 Given a permutation which contains no repeated number, find its index in all the permutations of these numbers, which are ordered in lexicograp ...
  • 轉載自https://www.jetbrains.com/help/idea/using-intellij-idea-as-the-vim-editor.html This feature is only supported in the Ultimate edition. The followin ...
  • 原文地址: "How to build applications with OpenCV inside the "Microsoft Visual Studio" " 我的博客: "SHLLL的小站" \ "Github" \ "CSDN" \ "博客園" \ "簡書" 前言: OpenCV是一個開 ...
  • 後端開發:1、高級java軟體架構師實戰培訓視頻教程2、大型SpringMVC,Mybatis,Redis,Solr,Nginx,SSM分散式電商項目視頻教程3、Spark Streaming實時流處理項目實戰4、Java校招面試 Google面試官親授5、Java開發企業級許可權管理系統6、Java ...
  • 信號量 IPC 原理 信號量通信機制主要用來實現進程間同步,避免併發訪問共用資源。信號量可以標識系統可用資源的個數。最簡單的信號量為二元信號量 下圖為 Linux 信號量通信機制的概念圖。在實際應用中,兩個進程通信可能會使用多個信號量,因此,Linux 在管理時以信號量集合的概念來管理。 通常所說的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...