RelatedManager
¶"关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。 它存在于下面两种情况:
ForeignKey
关系的“另一边”。
像这样:
from django.db import models
class Reporter(models.Model):
# ...
pass
class Article(models.Model):
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
在上面的例子中,reporter.article_set
管理器将拥有以下方法。
ManyToManyField
关系的两边:
class Topping(models.Model):
# ...
pass
class Pizza(models.Model):
toppings = models.ManyToManyField(Topping)
这个例子中,topping.pizza_set
和pizza.toppings
两个管理器都将拥有以下方法。
add
(*objs, bulk=True)¶添加一指定的模型对象到关联的对象集中。
例如:
>>> 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()
方法,而是由QuerySet.bulk_create()
创建关系。 如果你需要在关系被创建时执行一些自定义的逻辑,请监听m2m_changed
信号。
create
(**kwargs)¶创建一个新的对象,将它保存并放在关联的对象集中。 返回新创建的对象:
>>> b = Blog.objects.get(id=1)
>>> e = b.entry_set.create(
... headline='Hello',
... body_text='Hi',
... pub_date=datetime.date(2005, 1, 1)
... )
# 这里不需要调用e.save() — 它已经被保存。
这完全等价于(不过更加简洁于):
>>> 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
。
remove
(*objs)¶从关联对象集中移除指定的模型对象:
>>> 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
信号。
对于ForeignKey
对象,这个方法仅在null=True
时存在。 如果关联的字段不能设置为None
(NULL
),则这个对象在添加到另一个关联之前不能移除关联。 在上面的例子中,从e
从b.entry_set()
中删除等价于e.blog = None
,由于blog
的ForeignKey
没有设置null=True
,这个操作是非法的。
对于ForeignKey
对象,该方法接受一个bulk
参数来控制它如何执行操作。
如果为True
(默认值),QuerySet.update()
会被使用。
而如果bulk=False
,会在每个单独的模型实例上调用save()
方法。 这会触发pre_save
和post_save
,它们会消耗一定的性能。
clear
()¶从关联对象集中移除一切对象。
>>> b = Blog.objects.get(id=1)
>>> b.entry_set.clear()
注意这样不会删除对象 — 只会删除它们之间的关联。
就像remove()
方法一样,clear()
只能在null=True
的ForeignKey
上被调用,也可以接受bulk
关键字参数。
set
(objs, bulk=True, clear=False)¶替换相关对象集:
>>> new_list = [obj1, obj2, obj3]
>>> e.related_set.set(new_list)
此方法接受clear
参数来控制如何执行操作。 如果False
(默认值),则使用remove()
删除新集中缺少的元素,只添加新元素。
如果clear=True
,则调用clear()
方法,同时添加整个集合。
bulk
参数传递给add()
。
请注意,由于set()
是一个复合操作,因此受竞争条件限制。 例如,可以在调用clear()
和调用add()
之间的新数据库中添加新对象。
注
请注意,add()
,create()
,remove()
,clear()
和set()
都可以立即对所有类型的相关字段进行数据库更改。 换句话说,在关联的任何一端,都不需要再调用save()
方法。
另外,如果你对一个多对多关系使用中介模型,那么add()
、create()
、remove()
和set()
方法将被禁用。
如果你使用prefetch_related()
,那么add()
、remove()
、clear()
和set()
方法将清除预取的缓存。
添加了上述清除预取缓存。
2017年9月6日