关联对象参考

class RelatedManager

“关系管理器”是一个用于处理一对多和多对多关系的管理器。在以下两种情况用到:

  • ForeignKey 关系的“另一边”。即:

    1. from django.db import models
    2. class Blog(models.Model):
    3. # ...
    4. pass
    5. class Entry(models.Model):
    6. blog = models.ForeignKey(Blog, on_delete=models.CASCADE, null=True)

    In the above example, the methods below will be available on the manager blog.entry_set.

  • ManyToManyField 关系的两边:

    1. class Topping(models.Model):
    2. # ...
    3. pass
    4. class Pizza(models.Model):
    5. toppings = models.ManyToManyField(Topping)

    在这个例子中,下文列出的方法在 topping.pizza_setpizza.toppings 中均可用。

  • add(\objs, bulk=True, through_defaults=None*)

    将指定的模型对象加入关联对象集。

    举例:

    1. >>> b = Blog.objects.get(id=1)
    2. >>> e = Entry.objects.get(id=234)
    3. >>> 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_addpost_add 动作。

    在已经存在的关系上使用 add() 不会重复关系,但仍然会触发信号。

    对于多对多关系,add() 接受模型实例或字段值,通常是主键,作为 *objs 参数。

    如果需要的话,使用 through_defaults 参数为新的 中间模型 实例指定值。你可以使用可调用对象作为 through_defaults 字典中的值,它们将在创建任何中间实例之前被执行一次。

  • create(through_defaults=None, \*kwargs*)

    创建一个新的对象,将其保存并放入关联对象集。返回新创建的对象:

    1. >>> b = Blog.objects.get(id=1)
    2. >>> e = b.entry_set.create(
    3. ... headline='Hello',
    4. ... body_text='Hi',
    5. ... pub_date=datetime.date(2005, 1, 1)
    6. ... )
    7. # No need to call e.save() at this point -- it's already been saved.

    这相当于(但更简单):

    1. >>> b = Blog.objects.get(id=1)
    2. >>> e = Entry(
    3. ... blog=b,
    4. ... headline='Hello',
    5. ... body_text='Hi',
    6. ... pub_date=datetime.date(2005, 1, 1)
    7. ... )
    8. >>> e.save(force_insert=True)

    无需指定定义了模型间关系的关键字参数。在上述例子中,我们并未向 create() 传递参数 blog。Django 知道要将新 Entry 对象的 blog 字段设置为 b

    如果需要的话,使用 through_defaults 参数为新的 中间模型 实例指定值。你可以使用可调用对象作为 through_defaults 字典中的值。

  • remove(\objs, bulk=True*)

    从关联对象集中删除指定的模型对象:

    1. >>> b = Blog.objects.get(id=1)
    2. >>> e = Entry.objects.get(id=234)
    3. >>> 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 时,这个方法才存在。如果相关字段不能设置为 NoneNULL),那么一个对象就不能从一个关系中删除而不被添加到另一个关系中。在上面的例子中,从 b.entry_set() 中删除 e 相当于做了 e.blog = None,由于 blog ForeignKey` 没有 null=True,所以这是无效的。

    对于 ForeignKey 对象,这个方法接受一个 bulk 参数来控制如何执行操作。如果 True (默认),则使用 QuerySet.update()。如果 bulk=False,则调用每个单独模型实例的 save() 方法。这将触发 pre_savepost_save 信号,并以牺牲性能为代价。

    对于多对多关系,bulk 关键字参数不存在。

  • clear(bulk=True)

    从关联对象集中删除所有对象:

    1. >>> b = Blog.objects.get(id=1)
    2. >>> b.entry_set.clear()

    请注意,这并不会删除相关的对象——只是将它们脱离关联。

    remove() 一样,clear() 只在 ForeignKey 上可用,其中 null=True,而且它还接受 bulk 关键字参数。

    对于多对多关系,bulk 关键字参数不存在。

  • set(objs, bulk=True, clear=False, through_defaults=None)

    替换一组关联对象:

    1. >>> new_list = [obj1, obj2, obj3]
    2. >>> 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()create()remove()clear()set() 都会对所有类型的相关字段立即应用数据库变化。换句话说,没有必要在关系的任何一端调用 save()

如果使用 prefetch_related()add()remove()clear()set() 方法会清除预取缓存。