如何在模型的save方法中访问ManyToManyField?

时间:2019-10-06 04:02:11

标签: django django-models

我知道我是第一个问这个问题的人,但是我找不到答案,所以请不要吃我。

如果我有一个model和一个field的{​​{1}};我知道我可以在保存之前获取所选对象,但这对所选对象已更改没有帮助。

ManyToManyField

models.py

1 个答案:

答案 0 :(得分:0)

根据您对问题的措辞方式,我认为您对ManyToManyField在幕后实际发生的事情感到困惑(从现在开始,我将其称为M2M),因此我将尝试使用以下模型进行解释:

class Topping(models.Model):
    name = models.CharField(max_length=30)

class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings = models.ManyToManyField(Topping)

当我们声明一个M2M字段时,Django在后台创建一个贯通模型,在这种情况下,它看起来像这样:

class ThroughModel(models.Model):
    topping = models.ForeignKey(Topping)
    pizza models.ForeignKey(Pizza)

这用于将模型链接在一起,并且除非存储在through字段中的M2M关键字来创建自己的模型,否则不会存储在数据库中。

在可以实际链接Pizza中的ToppingM2M模型之前,您需要 必须已经保存了实例:

>>> t1 = Topping(name='pepperoni')
>>> t2 = Topping(name='sausage')
>>> t3 = Topping(name='ham')
>>> Topping.objects.bulk_create([
>>> t1, t2, t3
>>> ])
>>>
>>> pizza = Pizza(name='meat lovers')

现在,如何将数据添加到M2M字段中?像这样:

>>> pizza.toppings.add(t1, t2, t3)

但是按原样,这会引发:

  

ValueError:“ Pizza”实例需要具有主键值才能使用多对多关系。

因为pizza实例未保存

>>> pizza.save()
>>> pizza.toppings.add(t1, t2, t3)
>>>
>>> print('no error thrown now!')

您还可以通过传递主键而不是实例来添加toppings

>>> pk = Toppings.objects.first().pk
>>> pk
1
>>> pizza = Pizza.objects.create(name='pepperoni pizza')
>>> pizza.toppings.add(pk)

最后,要从给定的披萨实例中获取toppings

>>> pizza.toppings.all()
<QuerySet [<Toppings: Toppings object (1)>, <Toppings: Toppings object (2)>, <Toppings: Toppings object (3)>]>

请务必注意,从M2M 要求 2个数据库查询中获取值,实际上并没有解决方法。

最后,要真正回答您的问题,您可以执行以下操作来访问M2M内的save字段:

class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings = models.ManyToManyField(Topping)

    def save(self, *args): # args will be M2M data
        super().save() # now that the instance is saved, we can access toppings
        if args:
            self.toppings.add(*args)

        print(self.toppings.all())

用法示例:

>>> pizza = Pizza(name='sausage and ham')
>>> pizza.save(2, 3)
<QuerySet [<Toppings: Toppings object (2)>, <Toppings: Toppings object (3)>]>
# this is from the print inside of save

我的示例模型来自文档的prefetch_related部分,但是如果您想了解更多有关ManyToManyFields的信息,建议您通读this部分。