关联对象参考
class RelatedManager
“关系管理器”是一个用于处理一对多和多对多关系的管理器。在以下两种情况用到:
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` 中均可用。
add
(*objs, bulk=True, through_defaults=None)aadd
(*objs, bulk=True, through_defaults=None)异步版本:
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
字典中的值,它们将在创建任何中间实例之前被执行一次。Changed in Django 4.2:
已添加了
aadd()
方法。create
(through_defaults=None, **kwargs)acreate
(through_defaults=None, **kwargs)异步版本:
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)
无需指定定义了模型间关系的关键字参数。在上述例子中,我们并未向
create()
传递参数blog
。Django 知道要将新Entry
对象的blog
字段设置为b
。如果需要的话,使用
through_defaults
参数为新的 中间模型 实例指定值。你可以使用可调用对象作为through_defaults
字典中的值。Changed in Django 4.1:
acreate()
方法已添加。remove
(*objs, bulk=True)aremove
(*objs, bulk=True)异步版本:
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
关键字参数不存在。Changed in Django 4.2:
已添加了
aremove()
方法。clear
(bulk=True)aclear
(bulk=True)异步版本:
aclear
从相关对象集中删除所有对象:
>>> b = Blog.objects.get(id=1)
>>> b.entry_set.clear()
请注意,这并不会删除相关的对象——只是将它们脱离关联。
和
remove()
一样,clear()
只在 ForeignKey 上可用,其中null=True
,而且它还接受bulk
关键字参数。对于多对多关系,
bulk
关键字参数不存在。Changed in Django 4.2:
已添加了
aclear()
方法。set
(objs, bulk=True, clear=False, through_defaults=None)aset
(objs, bulk=True, clear=False, through_defaults=None)异步版本:
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
字典中的值,它们将在创建任何中间实例之前被执行一次。Changed in Django 4.2:
已添加了
aset()
方法。
备注
请注意,add()
, aadd()
, create()
, acreate()
, remove()
, aremove()
, clear()
, aclear()
, set()
, 和 aset()
对于所有类型的相关字段都会立即应用数据库更改。换句话说,在关系的两端都不需要调用 save()
/asave()
。
如果你使用 prefetch_related(),那么 add()
, aadd()
, remove()
, aremove()
, clear()
, aclear()
, set()
, 和 aset()
方法会清除预取的缓存。