Django related objects reference

宫铭
2023-12-01

https://docs.djangoproject.com/en/2.1/ref/models/relations/

RelatedManager

关系管理器用于 一对多、 多对多关系中。包括:

  1. ForeignKey关系的另外一端(即没有添加ForeignKey字段的model 一端可以使用关系管理器)

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date pulbished')

    def was_published_recently(self):
        return self.pub_date >= timezone.now()

    def __str__(self):
        return "Question:%s" % self.question_text


class Choice(models.Model):
    question = models.ForeignKey(Question,on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return "Choice:%s,%s" % (str(self.question), self.choice_text)

这样,就可以使用:Quesion.choice_set

  1. 多对多关系的两边都可以使用。
class Topping(models.Model):
    # ...
    pass

class Pizza(models.Model):
    toppings = models.ManyToManyField(Topping)

topping.pizza_set 和 pizza.toppings 都是正确的。

add 方法add(*objs, bulk=True)

用于将特定的model 对象加入到相关对象set 中。

例如:

In [16]: c=Choice(choice_text="test",votes=0)
In [18]: c.save()
In [19]: q.choice_set.add(c)

在调用add 方法时,会调用对应的c.save()方法来执行更新。如在调用add方法后,Choice对象会添加更新了question的信息,另外,Question对象上会多关联一个Choice对象。例如:

In [19]: q.choice_set.add(c)

In [20]: q.choice_set.all()
Out[20]: <QuerySet [<Choice: Choice:Question:what's new?,test>]>

In [21]: c.question
Out[21]: <Question: Question:what's new?>

注意:在调用add(object)之前,需要object 已经保存过(调用过save方法),否则会跑错,例如:

In [16]: c=Choice(choice_text="test",votes=0)

In [17]: q.choice_set.add(c)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-17-39833237dde1> in <module>()
----> 1 q.choice_set.add(c)

~/.pyenv/versions/3.6.0/lib/python3.6/site-packages/django/db/models/fields/related_descriptors.py in add(self, *objs, **kwargs)
    591                         raise ValueError(
    592                             "%r instance isn't saved. Use bulk=False or save "
--> 593                             "the object first." % obj
    594                         )
    595                     pks.append(obj.pk)

ValueError: <Choice: Choice:Question:what's new?,test> instance isn't saved. Use bulk=False or save the object first.

或者如果你觉得自己调用save 比较麻烦的话,可以通过add(object,bulk=False)的方式,要求关联管理器来帮你调用c.save函数。例如:

In [37]: c=Choice(choice_text="test bulk",votes=1)

In [38]: q.choice_set.add(c,bulk=False)

In [39]: c.question
Out[39]: <Question: Question:what's new?>

注意
在多对多关系中,调用add方法不会调用任何的save 函数(不支持bulk参数)。但是,你可以调用 QuerySet.bulk_create()。如果你需要在关系创建的时候,执行自定义的逻辑,可以监听m2m_changed信号,该信号会触发pre_add,post_add动作。

create 方法create(**kwargs)

方法作用:创建一个新对象,并将对象保存并放到relate object set 中,并返回新创建的对象。

In [40]: c=q.choice_set.create(choice_text="create method",votes=2)

In [42]: c.question
Out[42]: <Question: Question:what's new?>

上述代码等同于:

In [46]: q=Question.objects.get(pk=1)

In [44]: c=Choice(question=q,choice_text="normal create",votes=1)

In [45]: c.save(force_insert=True)

remove 方法remove(*objs, bulk=True)

将相关对象从关联对象集中移除。和add()方法类似,会调用c.save()函数来执行更新操作。对于多对多关系中,调用remove 方法 会导致QuerySet.delete函数的调用(因此,则不会调用任何的save方法)。如果你想在执行关系删除的时候,执行自定义的代码,则可以监听m2m_changed信号。

在ForeiginKey这端,只有 ForeignKey 字段的null 属性为True 时,才能调用remove方法,即如下形式,允许question字段为空。因为调用remove 等价于choice.question=None。

class Choice(models.Model):
    question = models.ForeignKey(Question,on_delete=models.CASCADE, null=True)

对于ForeignKey场景下,bulk属性的作用同add。默认情况下bulk =True,执行的更新操作(即需要对象之前调用过save 方法)

在多对多关系中,不支持bulk参数。

clear 方法clear(bulk=True)

清除所有的关联关系。
注意:该方法不会删除对象,而只是清除了关系。同remove 方法,需要Foreginkey 端支持null =True,可以设置为空。

set 方法set(objs, bulk=True, clear=False)

重置关联关系。

该方法有一个clear 参数。如果clear=False ,则将不再objes 中的元素使用remove()方法移除。如果clear=True,则首先调用clear()方法将之前的元素全部删除掉,再将集合中的元素整个删除。

注意
如果你使用了中间模型(保存多对多的关系),则add,create,remove,set方法都不能调用

 类似资料:

相关阅读

相关文章

相关问答