「關聯管理器」是用於一對多或多對多關聯情境中的管理器。這發生在兩種情況下:
ForeignKey
關聯的「另一端」。也就是說:
from django.db import models
class Blog(models.Model):
# ...
pass
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, null=True)
在上述範例中,以下的方法將可在管理器 blog.entry_set
上使用。
ManyToManyField
關聯的兩端:
class Topping(models.Model):
# ...
pass
class Pizza(models.Model):
toppings = models.ManyToManyField(Topping)
在此範例中,以下的方法將可在 topping.pizza_set
和 pizza.toppings
上使用。
非同步版本: aadd
將指定的模型物件新增至關聯物件集合。
範例
>>> b = Blog.objects.get(id=1)
>>> e = Entry.objects.get(id=234)
>>> b.entry_set.add(e) # Associates Entry e with Blog b.
在上述範例中,就 ForeignKey
關係而言,會使用 QuerySet.update()
來執行更新。這需要物件已事先儲存。
您可以使用 bulk=False
引數,改由關聯管理器透過呼叫 e.save()
來執行更新。
然而,將 add()
用於多對多關係時,不會呼叫任何 save()
方法 (不存在 bulk
引數),而是使用 QuerySet.bulk_create()
來建立關聯。如果您需要在建立關聯時執行一些自訂邏輯,請監聽 m2m_changed
訊號,這將會觸發 pre_add
和 post_add
動作。
在已存在的關聯上使用 add()
不會重複關聯,但仍會觸發訊號。
對於多對多關係,add()
接受模型實例或欄位值 (通常是主鍵) 作為 *objs
引數。
使用 through_defaults
引數來指定新的 中間模型 實例的值 (如果需要)。您可以在 through_defaults
字典中使用可呼叫物件作為值,這些值將在建立任何中間實例之前評估一次。
非同步版本: acreate
建立一個新的物件、儲存它並將其放入關聯物件集合。傳回新建立的物件。
>>> b = Blog.objects.get(id=1)
>>> e = b.entry_set.create(
... headline="Hello", body_text="Hi", pub_date=datetime.date(2005, 1, 1)
... )
# No need to call e.save() at this point -- it's already been saved.
這等同於 (但比它更簡單):
>>> b = Blog.objects.get(id=1)
>>> e = Entry(blog=b, headline="Hello", body_text="Hi", pub_date=datetime.date(2005, 1, 1))
>>> e.save(force_insert=True)
請注意,不需要指定定義關聯的模型之關鍵字引數。在上述範例中,我們不會將參數 blog
傳遞給 create()
。Django 會判斷新的 Entry
物件的 blog
欄位應設定為 b
。
使用 through_defaults
引數來指定新的 中間模型 實例的值 (如果需要)。您可以在 through_defaults
字典中使用可呼叫物件作為值。
非同步版本: aremove
從關聯物件集合中移除指定的模型物件。
>>> b = Blog.objects.get(id=1)
>>> e = Entry.objects.get(id=234)
>>> b.entry_set.remove(e) # Disassociates Entry e from Blog b.
類似於 add()
,在上述範例中會呼叫 e.save()
來執行更新。然而,將 remove()
用於多對多關係時,會使用 QuerySet.delete()
來刪除關聯,這表示不會呼叫模型 save()
方法;如果您希望在刪除關聯時執行自訂程式碼,請監聽 m2m_changed
訊號。
對於多對多關係,remove()
接受模型實例或欄位值 (通常是主鍵) 作為 *objs
引數。
對於 ForeignKey
物件,只有在 null=True
時才存在此方法。如果相關欄位無法設定為 None
(NULL
),則物件無法在不新增到另一個關聯的情況下,從關聯中移除。在上述範例中,從 b.entry_set()
中移除 e
等同於執行 e.blog = None
,而且因為 blog
ForeignKey
沒有 null=True
,因此這是無效的。
對於 ForeignKey
物件,此方法接受一個 bulk
參數來控制操作的執行方式。如果 True
(預設值),則會使用 QuerySet.update()
。如果 bulk=False
,則會改為呼叫每個個別模型實例的 save()
方法。這會觸發 pre_save
和 post_save
訊號,但會犧牲效能。
對於多對多關係,bulk
關鍵字參數不存在。
非同步版本: aclear
從相關物件集合中移除所有物件
>>> b = Blog.objects.get(id=1)
>>> b.entry_set.clear()
請注意,這不會刪除相關物件,只是解除它們的關聯。
就像 remove()
一樣,clear()
僅在 ForeignKey
的 null=True
時可用,並且它也接受 bulk
關鍵字參數。
對於多對多關係,bulk
關鍵字參數不存在。
非同步版本: aset
取代相關物件的集合
>>> new_list = [obj1, obj2, obj3]
>>> e.related_set.set(new_list)
此方法接受一個 clear
參數來控制操作的執行方式。如果 False
(預設值),則會使用 remove()
移除新集合中缺少的元素,並且只會加入新的元素。如果 clear=True
,則會改為呼叫 clear()
方法,並且一次加入整個集合。
對於 ForeignKey
物件,bulk
參數會傳遞給 add()
和 remove()
。
對於多對多關係,bulk
關鍵字參數不存在。
請注意,由於 set()
是一個複合操作,因此可能會受到競爭條件的影響。例如,新的物件可能會在呼叫 clear()
和呼叫 add()
之間被加入到資料庫中。
對於多對多關係,set()
接受一個模型實例或欄位值(通常是主鍵)的列表作為 objs
參數。
使用 through_defaults
引數來指定新的 中間模型 實例的值 (如果需要)。您可以在 through_defaults
字典中使用可呼叫物件作為值,這些值將在建立任何中間實例之前評估一次。
注意
請注意,add()
、aadd()
、create()
、acreate()
、remove()
、aremove()
、clear()
、aclear()
、set()
和 aset()
都會立即針對所有類型的相關欄位應用資料庫變更。換句話說,不需要在關係的任何一端呼叫 save()
/asave()
。
如果您使用 prefetch_related()
,則 add()
、aadd()
、remove()
、aremove()
、clear()
、aclear()
、set()
和 aset()
方法會清除預先擷取的快取。
_meta
API離線 (Django 5.1): HTML | PDF | ePub
由 Read the Docs 提供。