1. 程式人生 > >Django 2.1.3 文件-模型層-執行查詢

Django 2.1.3 文件-模型層-執行查詢

執行查詢


- - 譯自官方文件+自己的理解 --

一旦你建立了 資料模型,Django就會自動為你提供一個數據庫抽象API,讓你可以建立,檢索,更新和刪除物件。本文件介紹瞭如何使用此API。有關所有各種模型查詢選項的完整詳細資訊,請參閱 資料模型參考

在本指南(以及參考文獻)中,我們將使用以下模型,包含於Weblog應用程式中:
在這裡插入圖片描述


譯者注
1.譯者使用自己的4個模型來提供額外補充,模型定義如下,其中Book和Author是多對多關係,Book和Publish是多對一關係,Author和AuthorDetail是一對一關係:

class Author(models.Model):
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name

class AuthorDetail(models.Model):
    age = models.IntegerField()
    address = models.CharField(max_length=32,default="china")

    author = models.OneToOneField(to="Author",on_delete=models.CASCADE)
    def __str__(self):
        return self.author.name

class Publish(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()
    address = models.CharField(max_length=32, default="china-pub")
    def __str__(self):
        return self.name

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=6,decimal_places=2)
    cate_list = ((1,"敘事作品"),(2,"小說文學"),(3,"科幻文學"),(4,"隨筆"))
    category = models.IntegerField(choices=cate_list)

    authors = models.ManyToManyField(to="Author")
    publishs = models.ForeignKey(to="Publish",on_delete=models.CASCADE)

    def __str__(self):
        return "<"+self.name+">"

2.模型對應表中的資料如下:
(1)Author:
在這裡插入圖片描述
(2)AuthorDetail:
在這裡插入圖片描述
(3)Book:
在這裡插入圖片描述
(4)Publish:
在這裡插入圖片描述

1.建立物件

為了在Python物件中表示資料庫表資料,Django使用直觀的系統:模型類表示資料庫表,該類的例項表示資料庫表中的特定記錄。

要建立物件,請使用模型類的關鍵字引數對其進行例項化,然後呼叫save()以將其儲存到資料庫中。

這裡有一個例子:

def fun01_create_obj():
    p = Publish(name='機械',email='[email protected]',address='china')
    p.save()
if __name__ == "__main__":
    fun01_create_obj()

資料庫publish表中增加了一條內容
在這裡插入圖片描述
這會在幕後執行INSERTSQL語句。在您明確呼叫save()之前,Django不會訪問資料庫。

save()方法沒有返回值。

參見
save()採用了許多此處未描述的高階選項。有關save()完整的詳細資訊,請參閱文件 。
要在一條語句中建立和儲存物件,請使用 create()方法。↑

2.儲存對物件的修改

要儲存對已存在於資料庫中的物件的更改,請使用 save()。

給定已儲存到資料庫的一個Blog例項 b5,此示例更改其名稱並更新其在資料庫中的記錄:

def fun01_create_obj():
    p = Publish(name='機械',email='[email protected]',address='china')
    p.name = p.name+"append"
    p.save()
    print(p.name)
# 輸出結果
機械append

這會在幕後執行UPDATESQL語句。在您明確呼叫save()之前,Django不會訪問資料庫。

2.1 儲存ForeignKey 和 ManyToManyField 欄位

更新ForeignKey欄位的手段與儲存普通欄位的方式完全相同 - 只需將正確型別的物件分配給相關欄位即可。假設適當的Entry和Blog例項已經儲存到資料庫中,這個例子更新了一個Entry例項entry的blog屬性:
在這裡插入圖片描述
更新ManyToManyField方式略有不同 - 使用 add()欄位上的方法向關係新增記錄。此示例將Author例項 新增joe到entry物件:
在這裡插入圖片描述
要一次性新增多個ManyToManyField記錄,請在呼叫add()中包含多個引數 ,如下所示:
在這裡插入圖片描述
如果您嘗試分配或新增錯誤型別的物件,Django會提醒你。

3.檢索物件

要從資料庫中檢索物件,請在模型類上使用Manager構建一個 QuerySet

QuerySet表示資料庫中的物件集合。它可以有零個,一個或多個過濾器。過濾器根據給定的引數縮小查詢結果範圍。在SQL術語中,一個QuerySet就是SELECT語句,過濾器是限制子句,如WHERELIMIT

你可以使用模型中的Manager獲得QuerySet。每個模型至少有一個 Manager,預設情況下呼叫 objects。通過模型類直接訪問它,如下所示:在這裡插入圖片描述

註解
Managers 只能通過模型​​類訪問而不是模型例項訪問,以強制“表級”操作和“記錄級”操作之間的分離。↑

這Manager模型是QuerySets的主要來源。例如,Blog.objects.all()返回的QuerySet包含Blog資料庫中所有的物件。

3.1 檢索所有物件

從表中檢索物件的最簡單方法是獲取所有這些物件。為此,請使用 Manager中的all()方法:
在這裡插入圖片描述
all()方法返回資料庫中所有Entry物件的一個 QuerySet集合​​。

3.2 使用過濾器檢索特定物件

通過 all()返回的QuerySet描述資料庫中的表中的所有物件。但是,通常,您只需要選擇整個物件集的子集。

要建立此類子集,請優化初始的QuerySet,為其新增過濾條件。兩種最常見的改進方法QuerySet是:

  • **filter(kwargs)
    返回QuerySet包含與給定查詢引數匹配的新物件。
  • **exclude(kwargs)
    返回QuerySet包含與給定查詢引數不匹配的新物件。
    查詢引數(**kwargs在上面的函式定義中)應採用下面的欄位查詢中描述的格式。

例如,要獲取2006年的部落格條目的QuerySet,請使用下面的filter():
在這裡插入圖片描述
使用預設的manager類,它與以下內容相同:
在這裡插入圖片描述

3.2.1 過濾器鏈

QuerySet經過過濾器細化後還是一個QuerySet,因此可以將過濾器連結在一起。例如:
在這裡插入圖片描述
初始的QuerySet是資料庫中所有Entry物件,新增filter,然後exclude,然後是另一個filter。最終結果是QuerySet包含標題以“What”開頭的所有條目,這些條目是在2005年1月30日和當天之間釋出的。

3.2.2 使用過濾器的QuerySets是唯一的

每當你細化一個QuerySet,你就會得到一個全新的QuerySet,與以前的QuerySet沒有任何關係。每個細化都會建立一個獨立且不同的QuerySet,可以儲存,使用和重用。
在這裡插入圖片描述
這三者QuerySets是分開的。第一個是QuerySet包含所有條目的, 其中包含以“What”開頭的標題。第二個是第一個的子集,exclude排除了pub_date為今天以後的記錄。第三個是第一個的子集,filter選擇了pub_date為今天以後的記錄。初始的QuerySet(q1)不受細化過程的影響。

3.2.3 QuerySets是惰性的

QuerySets是懶惰的 - 建立一個 QuerySet不涉及任何資料庫活動的行為。可以一直疊加過濾器,Django將不實際執行查詢,直到QuerySet被 計算。看看這個例子:
在這裡插入圖片描述
雖然這看起來像訪問資料庫3次,但事實上它訪問資料庫中一次,在最後一行(print(q))。通常,在QuerySet在“詢問”它們之前,不會從資料庫中獲取結果 。執行此操作時,QuerySet通過訪問資料庫來計算 。有關何時進行計算的更多詳細資訊,請參閱 何時QuerySe進行計算

3.3 用get()檢索單個物件

filter()總會給你一個QuerySet,即使只有一個物件與查詢匹配 - 在這種情況下,QuerySet包含一個元素。

如果您知道只有一個物件與您的查詢匹配,則可以使用 Manager直接返回物件的 get()方法:
在這裡插入圖片描述
您可以在get()中使用任何查詢表示式 ,就像使用 filter()一樣- ,請參閱下面的欄位查詢部分。

請注意,使用get()和使用 filter()對於切片 [0]之間存在差異。如果沒有與查詢匹配的結果, get()則會引發DoesNotExist異常。此異常是正在執行查詢的模型類的屬性 - 因此在上面的程式碼中,如果沒有Entry主鍵為1的物件,Django將引發Entry.DoesNotExist錯誤。
在這裡插入圖片描述
同樣,如果多個專案與get()查詢匹配,Django會報錯 。在這種情況下,它會引發 MultipleObjectsReturned錯誤,這也是模型類本身的屬性。
在這裡插入圖片描述

3.4 其他QuerySet方法

在大多數情況下,你會使用all(), get(), filter()和 exclude()從資料庫中查詢物件。然而,這遠非一切; 有關所有QuerySet各種方法的完整列表,請參閱 QuerySet API參考

3.5 limit QuerySet

使用Python的陣列切片語法的子集將限制 QuerySet為一定數量的結果。這相當於SQL中的LIMITOFFSET子句。

例如,這將返回前5個物件(等價於 LIMIT 5):
Entry.objects.all()[:5]
這將返回第六個到第十個物件(OFFSET 5 LIMIT 5):
Entry.objects.all()[5:10]

不支援負下標(例如 Entry.objects.all()[-1])。

通常,切片QuerySet返回一個新的 QuerySet- 它不會再次查詢。例外情況是,如果您使用Python切片語法的“step”引數。例如,這實際上會執行查詢以返回前10 箇中每隔一個物件的列表:
Entry.objects.all()[:10:2]
禁止對切片查詢集進行進一步過濾或排序,因為它可能有多種模糊性。

要檢索單個物件而不是列表(例如SELECT foo FROM bar LIMIT 1),請使用簡單索引而不是切片。例如,在按標題字母順序排序條目之後,這將返回資料庫中的第一個Entry:
Entry.objects.order_by('headline')[0]
這大致相當於:
Entry.objects.order_by('headline')[0:1].get()

但請注意,如果沒有物件符合給定條件,則第一個將報IndexError錯誤,而第二個將報DoesNotExist錯誤。請參閱有關get()詳細資訊。

3.6 欄位查詢

欄位查詢就等同於指定SQL中的WHERE子句。它們被指定為QuerySet 方法filter(), exclude()和 get()的關鍵字引數。

基本查詢關鍵字引數採用這種形式field__lookuptype=value。(這是一個雙重下劃線)。例如:
Entry.objects.filter(pub_date__lte='2006-01-01')
將(粗略地)翻譯成以下SQL語句:
SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

查詢中指定的欄位必須是模型欄位的名稱。但有一個例外,如果是ForeignKey你可以為欄位名稱指定字尾的_id。在這種情況下,value引數應包含外部模型主鍵的原始值。例如:
Entry.objects.filter(blog_id=4)

如果傳遞無效的關鍵字引數,則會引發查詢函式 TypeError。

資料庫API支援大約24種查詢型別; 可以在 欄位查詢參考 中找到完整的參考。為了讓您瞭解可用的內容,以下是您可能會使用的一些常見查詢:

exact
“精確”匹配。例如:
Entry.objects.get(headline__exact="Cat bites dog")
將生成這樣的SQL:
SELECT ... WHERE headline = 'Cat bites dog';

如果您不提供查詢型別 - 也就是說,如果您的關鍵字引數不包含雙下劃線 - 則假定查詢型別為 exact。
例如,以下兩個語句是等效的:
在這裡插入圖片描述
這是為了方便,因為exact查詢是常見的情況。

iexact
不區分大小寫的匹配項。所以,查詢:
Blog.objects.get(name__iexact="beatles blog")
將會匹配標題為Beatles Blog, beatles blog 甚至 BeAtlES blOG.

contains
區分大小寫的模糊匹配。例如:
Entry.objects.get(headline__contains='Lennon')
SQL大概是這樣的:
SELECT ... WHERE headline LIKE '%Lennon%';

請注意,這將與標題Today Lennon honored匹配,但不與today lennon honored匹配。

還有一個不區分大小寫的版本icontains

startswith endswith
分別以xx開始和以xx結束。還有一些不區分大小寫的版本叫做istartswithiendswith
這幾個方法只是冰山一角。可以在 欄位查詢參考 中找到完整的 參考。

3.7 跨關係查詢

Django提供了一種強大而直觀的方式來“跟蹤”查詢中的關係,在後臺自動為您處理SQL 中的JOIN。要跨越關係,只需使用跨模型的相關欄位的欄位名稱,用雙下劃線分隔,直到到達所需的欄位。

這個例子檢索所有Entry與物件Blog,其name 為:‘Beatles Blog’
Entry.objects.filter(blog__name='Beatles Blog')

這種跨越可以像你想的那樣深。
它也可以反向。要引用“反向”關係,只需使用模型的小寫名稱即可。

這個例子檢索所有Blog具有至少一個物件Entry ,其headline包含’Lennon’:
Blog.objects.filter(entry__headline__contains='Lennon')

如果您要跨多個關係進行過濾,並且其中一箇中間模型沒有滿足過濾條件的值,Django會將其視為存在空(所有值都是NULL),但有效,物件存在。所有這些意味著不會引發任何錯誤。例如,在此過濾器中:

Blog.objects.filter(entry__authors__name='Lennon')

(如果存在相關Author模型),如果沒有author 與entry相關聯,則將其視為沒有name ,而不是因為缺失author而引發錯誤。通常這正是你想要發生的事情。可能令人困惑的唯一情況是你正在使用 isnull。例如:
Blog.objects.filter(entry__authors__name__isnull=True)

將返回有一個空的Blog物件,其中entry的author為空或者 author上的name為空。如果你不想要author為空,你可以寫:
Blog.objects.filter(entry__authors__isnull=False, entry__authors__name__isnull=True)

3.7.1 跨越多值關係

當您基於ManyToManyField過濾或反向ForeignKey,您可能會對兩種不同型別的過濾器感興趣。請考慮Blog/ Entry(Blog與Entry一對多關係)。我們可能有興趣找到一個部落格,其一個entry的標題中包含“Lennon”並於2008年釋出。或者我們可能希望找到一個entry的標題中帶有“Lennon”的部落格 以及一個entry的釋出日期是2008年,這些查詢都是可能的,並且在某些情況下有意義。

同樣的情況出現於 ManyToManyField。例如,如果Entry有一個tags屬性是ManyToManyField型別,我們可能想要找到一個entry連結到名為“music”和“bands”的tag,或者我們可能想要一個包含名稱為“music”且狀態為“public”的entry。

為了處理這兩種情況,Django有一種一致的處理 filter()呼叫方式。單個filter()中的所有內容同時應用以過濾掉符合所有這些要求的專案。連續 filter()呼叫進一步限制了物件集,但對於多值關係,它們適用於連結到主模型的任何物件,而不一定是先前filter()呼叫選擇的那些物件。

這可能聽起來有點令人困惑,所以希望一個例子可以澄清。要選擇所有entry標題中包含“Lennon”且2008年釋出的條目的部落格(同一entry滿足兩個條件),我們會寫:
在這裡插入圖片描述
要選擇entry的標題 中包含“Lennon”的所有部落格以及 2008年釋出的entry,我們會寫:
在這裡插入圖片描述
假設只有一個部落格的兩個條目都包含“Lennon”和2008年的條目,但是2008年的條目都沒有包含“Lennon”。第一個查詢不會返回任何部落格,但第二個查詢將返回該部落格。

在第二個示例中,第一個過濾器將查詢集限制為連結到標題中帶有“Lennon”的條目的所有部落格。第二個過濾器將部落格集進一步限制為也連結到2008年釋出的條目的部落格。第二個過濾器選擇的條目可能與第一個過濾器中的條目相同或不同。我們Blog使用每個過濾器語句過濾 專案,而不是Entry專案。

註解
如上所述,跨越多值關係的filter()查詢的行為不是等效實現的exclude()。相反,單個exclude() 呼叫中的條件不一定是指同一個專案。

例如,下面的查詢將排除部落格包含“Lennon”的標題,並在2008年出版的entry:
在這裡插入圖片描述
但是,與使用filter()時的行為不同 ,這不會限制基於滿足這兩個條件的條目的部落格。為了做到這一點,即選擇所有不包含 2008年釋出的“Lennon”條目的部落格,您需要進行兩次查詢:
在這裡插入圖片描述

3.8 過濾器可以引用模型上的欄位

在到目前為止給出的例子中,我們構造了過濾器,用於比較模型欄位的值和常量。但是,如果要將模型欄位的值與同一模型上的另一個欄位進行比較,該怎麼辦?

Django 允許使用 F函式 進行這樣的比較。作為查詢中模型欄位的引用的F()例項。然後,可以在查詢過濾器中使用這些引用來比較同一模型例項上的兩個不同欄位的值。

例如,要查詢comment比pingback多的所有部落格條目的列表,我們構造一個F()物件來引用pingback的計數,並F()在查詢中使用該物件:
在這裡插入圖片描述
Django支援對物件使用F()進行加法,減法,乘法,除法,模運算和冪運算,包括常量和其他F()物件。要查詢所有部落格條目的comment數量是pingback的兩倍以上 ,我們會修改查詢:
Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)

要查詢條目評級小於pingback計數和評論計數總和的所有條目,我們將發出查詢:
Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))

您還可以在F()中使用雙下劃線表示法來跨越物件查詢。F()具有雙下劃線的物件將引入訪問相關物件所需的任何連線。例如,要檢索作者姓名與部落格名稱相同的所有條目,我們可以發出查詢:
Entry.objects.filter(authors__name=F('blog__name')

對於日期和日期/時間欄位,您可以新增或減去 timedelta物件。以下內容將返回在釋出後超過3天內修改的所有條目:
在這裡插入圖片描述
F()物件通過.bitand() .bitor() .bitrightshift() .bitleftshift()這些方法支援支援位運算。例如:
F('somefield').bitand(16)

3.9 使用pk快速查詢

為方便起見,Django提供了一個pk快捷查詢方式,代表“主鍵”。
在示例Blog模型中,主鍵是id欄位,因此這三個語句是等效的:
在這裡插入圖片描述
使用pk不僅限於__exact查詢 - 可以組合任何查詢術語以pk對模型的主鍵執行查詢:
在這裡插入圖片描述
pk查詢也適用於連線。例如,這三個語句是等價的:
在這裡插入圖片描述

3.10 在LIKE語句中轉義百分號和下劃線

類似於SQL語句中的LIKE(如 iexact, contains,icontains,startswith,istartswith,endswith 和iendswith)將自動轉義LIKE語句使用的兩個特殊字元 -百分號和下劃線。(在一個LIKE 語句中,百分號表示多字元萬用字元,下劃線表示單字元萬用字元。)

例如,要檢索包含百分號的所有條目,只需像使用任何其他字元那樣使用百分號:
在這裡插入圖片描述
Django負責為你轉義; 生成的SQL看起來像這樣:
在這裡插入圖片描述
下劃線也是如此。百分號和下劃線都是透明處理的。

3.11 快取和QuerySets

每個QuerySet都包含一個快取,以最小化資料庫訪問。 瞭解它的工作原理將允許您編寫最有效的程式碼。

在新建立的QuerySet中,快取為空。第一次QuerySet被計算 - 發生一次資料庫查詢 - Django將查詢結果儲存在QuerySet快取中並返回已明確請求的結果(例如,QuerySet正在迭代的下一個元素)。隨後對QuerySet重用快取結果的評估。

記住這種快取行為,因為如果你沒有正確使用QuerySet ,它可能會擾亂你。例如,以下將建立兩個QuerySets,對它們進行計算,並拋棄它們:
在這裡插入圖片描述
這意味著相同的資料庫查詢將執行兩次,使資料庫負載加倍。此外,兩個列表可能不包含相同的資料庫記錄,因為Entry可能已在兩個請求之間的時間內中新增或刪除了。

要避免此問題,只需儲存 QuerySet並重復使用它:
在這裡插入圖片描述

3.11.1 什麼時候QuerySets不快取

查詢集並不總是快取其結果。僅計算部分查詢集時,將檢查快取,但如果未填充,則不會快取後續查詢返回的專案。具體而言,這意味著, 限制所述查詢集使用陣列切片或索引不會填充快取。

例如,在queryset物件中重複獲取某個索引將每次查詢資料庫:
在這裡插入圖片描述
但是,如果已經計算了整個查詢集,則將檢查快取:
在這裡插入圖片描述
以下是一些其他操作的示例,這些操作將導致整個查詢集被計算,從而填充快取:
在這裡插入圖片描述

4.使用Q物件進行復雜查詢

多個關鍵字查詢引數 - 例如在filter()方法中 - 是用“AND關係”連線在一起。如果需要執行更復雜的查詢(例如,帶OR語句的查詢),則可以使用Q 物件

Q 物件(django.db.models.Q)是用於封裝關鍵字引數集合的物件。這些關鍵字引數在上面的“欄位查詢”中指定。

例如,此Q物件封裝了一個LIKE查詢:

from django.db.models import Q
Q(question__startswith='What')

Q可以使用&|運算子組合物件。當在兩個Q物件上使用運算子時,它會生成一個新Q物件。

例如,此語句生成一個Q表示兩個"question__startswith"查詢的或:

Q(question__startswith='Who') | Q(question__startswith='What')

這相當於以下SQL WHERE子句:

WHERE question LIKE 'Who%' OR question LIKE 'What%'

您可以通過&|操作符合並組成任意複雜的Q物件,並使用括號分組。此外,Q 可以使用~運算子排除物件,允許組合同時結合普通查詢和~查詢:

def fun01_q():
    from django.db.models import Q
    all_book = Book.objects.all()
    print(all_book)
    print(all_book.filter(~Q(name__contains='喊')))
    print(all_book.filter(Q(name__contains='喊')|~Q(price__gt=20)))

if __name__ ==  "__main__":
    fun01_q()
# 輸出結果
<QuerySet [<Book: <吶喊>>, <Book: <哈利波特>>, <Book: <滅亡>>]>
<QuerySet [<Book: <哈利波特>>, <Book: <滅亡>>]>
<QuerySet [<Book: <吶喊>>, <Book: <滅亡>>]>

每個查詢函式(例如filter(), exclude(), get()),所需要的關鍵字引數也可以是一個或多個 Q物件作為位置(未命名的)引數。如果為查詢函式提供多個Q 物件引數,則用AND關係連線在一起。例如:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

大致翻譯成SQL:

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

查詢函式可以混合使用Q物件和關鍵字引數。提供給查詢函式的所有引數(無論是關鍵字引數還是Q 物件)都是AND連線在一起的。但是,如果提供了Q物件,則它必須位於任何關鍵字引數的定義之前。例如:

print(all_book.filter(
Q(name__contains='喊') | ~Q(price__gt=20),
name__contains='亡')
))
# 輸出結果
<QuerySet [<Book: <滅亡>>]>

但是,調換位置之後,會報錯:

print(all_book.filter(
name__contains='亡',
Q(name__contains='喊') | ~Q(price__gt=20)
))
# 輸出結果
 File "F:/zzzzz-wang/dj-proj/leanproj/orm.py", line 18
 print(all_book.filter(name__contains='亡',Q(name__contains='喊') | ~Q(price__gt=20)))
SyntaxError: positional argument follows keyword argument

Django單元測試中的OR查詢示例顯示了一些可能的用法Q。

5. 比較物件

要比較兩個模型例項,只需使用標準的Python比較運算子,即雙等號:==。在幕後,比較兩個模型的主鍵值。

使用Entry上面的示例,以下兩個print中的語句是等效的:

def fun02_compare_obj():
    b1 = Book.objects.filter(name__contains='喊').first()
    b2 = Book.objects.filter(name__contains='吶').first()
    print(b1 == b2)
    print(b1.id == b2.id)
if __name__ ==  "__main__":
    fun02_compare_obj()
# 輸出結果
True
True

如果未呼叫模型的主鍵id,也沒問題,因為無論你使用什麼來比較,將始終使用主鍵。例如,如果呼叫模型的主鍵欄位name,這兩個語句是等效的:

b1 == b2
b1.name == b2.name

6. 刪除物件

刪除方法為 delete()。此方法立即刪除物件並返回已刪除的物件數量以及包含每個物件型別的刪除數的字典。例如(刪掉書籍《吶喊》):

>>>b1 = Book.objects.filter(name="吶喊")
>>>b1.delete()
(1, {'model_layer.Book_authors': 0, 'model_layer.Book': 1})

您也可以批量刪除物件。每個QuerySet都有一個 delete()方法,用於刪除QuerySet中的所有成員。

例如,這會刪除價格少於25塊錢的書籍:

def fun03_delete_obj():
    all_book = Book.objects.all()
    print(all_book)
    print(all_book.filter(price__lt=25).delete())

if __name__ ==  "__main__":
    fun03_delete_obj()
# 輸出結果
<QuerySet [<Book: <吶喊>>, <Book: <哈利波特>>, <Book: <滅亡>>]>
(2, {'model_layer.Book_authors': 0, 'model_layer.Book': 2})

請記住,只要有可能,這將完全在SQL中執行,所以在此過程中不一定會呼叫單個物件例項的delete()方法。如果您在模型類上提供了自定義delete()方法並希望確保呼叫它,則需要“手動”刪除該模型的例項(例如,通過迭代 QuerySet並單獨呼叫每個物件的delete())而不是使用 QuerySet的批量 delete()方法。

當Django刪除一個物件時,預設情況下它會模擬SQL約束的行為ON DELETE CASCADE (級聯刪除)- 換句話說,任何具有指向要刪除的物件的外來鍵的物件都將隨之刪除。例如,我們在Book表中定義它的一個外來鍵是Publish,屬性是on_delete=models.CASCADE這意味著,如果一個出版社物件被刪除,與之關聯的書籍就會全部刪除:

def fun03_delete_obj_cascade():
    p = Publish.objects.get(pk=1)
    print(p.delete())

if __name__ ==  "__main__":
    fun03_delete_obj_cascade()
# 輸出結果
(3, {'model_layer.Book_authors': 0, 'model_layer.Book': 2, 'model_layer.Publish': 1})

這種級聯行為可以通過 ForeignKey欄位中的on_delete引數自定義(不一定要刪除,也可能什麼都不做)。

請注意,delete()是唯一沒有在Manager上公開的QuerySet方法 。這是一種安全機制,可以防止您意外請求Entry.objects.delete()刪除所有條目。如果您確實要刪除所有物件,則必須顯式請求完整的查詢集,例如:
Entry.objects.all().delete()

7. 複製模型例項

雖然沒有用於複製模型例項的內建方法,但可以輕鬆建立複製了所有欄位值的新例項。在最簡單的情況下,您可以設定pk為None。使用我們的部落格示例:

blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1

blog.pk = None
blog.save() # blog.pk == 2

如果使用繼承,事情會變得更復雜。考慮一個子類 Blog:

class ThemeBlog(Blog):
    theme = models.CharField(max_length=200)

django_blog = ThemeBlog(name=
            
           

相關推薦

Django 2.1.3 -模型-執行查詢

執行查詢 1.建立物件 2.儲存對物件的修改 2.1 儲存ForeignKey 和 ManyToManyField 欄位 3.檢索物件 3.1 檢索所有物件 3.2 使用過濾器檢索特定物件

Django 2.1.3 -模型 支援的資料庫

資料庫 1. 一般注意事項 1.1 持久連線 1.2 連線管理 1.3 警告 1.4 編碼 2. Mysql注意事項 2.1 版本支援 2.2 儲存引擎 2.3 MySQL DB AP

Django 2.1.3 模型 Meta選項

模型Meta選項 1. 可用 Meta選項 1.1 db_table 1.1.1 表名 慢慢補充 本文件介紹了可以在class Meta內部為模型提供的所有可能的元資料選項。 1. 可用 M

Django 2.1.3 -模型-QuerySet 方法參考

QuerySetAPI參考 1.什麼時候QuerySet求值 2. 醃製(pickling)QuerySets 3. QuerySet API 3.1 返回新QuerySets的方法 filter() exclu

Django 2.1.3 -模型-模型

模型 1.快速上手 2.使用模型 3.欄位 3.1欄位型別 3.2欄位選項 3.3自動設定主鍵 3.4備註名 3.5關聯關係 3.5.1 多對一 3.5.2 多對多

Django 2.1.3 -檢視-生成PDF

用Django輸出PDF 本文件介紹瞭如何使用Django檢視動態輸出PDF檔案。這是通過優秀的開源Python PDF庫ReportLab 實現的。 動態生成PDF檔案的優點是,您可以為不同目的建立自定義PDF,例如,針對不同使用者或不同內容。 例如,Django在kuspor

Django 2.1.3 知識點整理 - 問題

一、訪問靜態檔案404 解決方法:網上一堆亂七八糟方案也沒解決,自己改出解決方案 0.我的靜態檔案目錄層級 projectname/static/appname/css/xx.css 1.修改settings.py STATIC_URL = '/static/' STATIC_ROOT = os.p

Django 2.1.3 開發程序 配置

Django 設定 1. 基礎 2. 指定配置檔案 2.1 django-admin 功能 2.2 在伺服器上(mod_wsgi) 3.預設設定 4. 在其他地方使用settings 5. 在執行時更改設定

Django 2.1.3 -模板-人性化

人性化過濾器 apnumber intcomma intword naturalday naturaltime ordinal django.contrib.humanize 一組Django模板 過濾器,用於為資料

Django 2.1.3 -模板-語言概述

模板語言概述 1. 模板 2. 變數 3. 過濾器 4. 標籤 5. 註釋 6. 模板繼承 7. 自動HTML轉義 7.1 如何關閉它 7.1.1 對於個別變數 7.1.2 對於模板塊

Django 2.1.3 -模板-概述

模板 1. 模板引擎的支援 1.1 配置 1.2 用法 1.3 內建後端 1.3.1 DjangoTemplates(預設後端) 1.3.2 Jinja2 1.3.3 自定義後端

Django 2.1.3 開發程序 完整設定列表

設定 1. 核心設定 ADMINS ALLOWED_HOSTS APPEND_SLASH 1.1 快取 CACHES BACKEND KEY_FUNCTION K

django 2.1官方翻譯-模板(進行中)

django的官方文件在transifex上翻譯,本來想貢獻一下,結果發現那個介面實在是受不了。自己翻吧 模板 作為一個Web框架,Django需要一種動態生成HTML的便捷方式。最常見的方法是使用模板。模板包含HTML輸出的靜態部分以及能插入動態內容的一些特殊語法。有關使用模板建立HT

Django 2.1.3 模型 多對一關係 例子

使用 ForeignKey 來定義一個多對一的關係。 from django.db import models class Reporter(models.Model): first_name = models.CharField(max_length=30) last

Django 2.1.3 模型 Model類

文章目錄 屬性 objects 完 本文件涵蓋了該Model類的功能。有關模型的更多資訊,請參閱模型參考指南的完整列表。 屬性 objects 每個非抽象Model類都必須新增一個 Manager例項。Dj

Django 2.1.3 模型 自定義查詢

自定義查詢 1.一個簡單的查詢示例 1.1 具體步驟 2.簡單的轉換器示例 3.編寫一個高效的 abs__lt 查詢 4.Transformer 雙向示例 5.為現有查詢的關係編寫一個代替實現 6.Django如何確

Django 2.1.3 模型 索引

索引 Index 選項 fields name db_tablespace 索引類可輕鬆建立資料庫索引。可以通過Meta.indexes選項新增它們 。本文件解釋了索引的API引用和index 選項。 引用內

Django 2.1.3 模型 欄位型別

目錄 1.欄位選項 null blank choices db_column db_index db_tablespace default editable error_messages

建立專案以及django路由規則(環境必備 python3.7 django 2.1.3

本人使用pycharm建立django專案首先選擇django建立專案建立完成目錄如下在終端鍵入命令python manage.py startapp model1,python manage.py startapp model2 自動生成模組model1和model2終端鍵入python manage.py

DL4J中文/模型/

什麼是層? 神經網路配置中的每一層表示隱藏單元的單元。當層堆疊在一起時,它們代表了一個深度神經網路。 使用層 在Eclipse DL4J中可用的所有層都可以用在多層網路或計算圖中。當配置一個神經網路時,你傳遞層配置,網路會為你例項化該層。 層VS頂點 如果你正在配置諸如Incep