如何在一对多关系中级联更新?

时间:2016-10-19 13:17:53

标签: django django-orm

我认为最好用一个例子来解释。

class GrandParent(models.Model):
    pass

class Parent(models.Model):
    grandparent = models.ForeignKey(GrandParent, null=True, blank=True, default=None)    

class Child(models.Model):
    parent = models.ForeignKey(Parent, null=True, blank=True, default=None)
    grandparent = models.ForeignKey(GrandParent, null=True, blank=True, default=None)    

所以我们有三个班级。 Child具有Parent和GrandParent的外键,而Parent具有GrandParent的外键。

在Django Admin区域中,我单击父记录(P1)并将其外键设置为GrandParent记录(GP1)。

我希望这可以级联到所有Child记录。换句话说,每个已经有P1外键的子记录都应该自动获得GP1的外键。

是否有Django方法可以做到这一点?

谢谢。

1 个答案:

答案 0 :(得分:1)

一旦您需要真正的业务逻辑,我个人就不会使用管理页面,但这里的答案是:

如果您只需要从管理页面执行此操作,则只需覆盖管理员保存功能

即可
class ParentAdmin(admin.ModelAdmin):
    list_display = ('id', 'parent', )

    def save_model(self, request, obj, form, change):
        obj.save()
        for c in obj.child_set.all():
            if c.granparent != obj.grandparent:
                c.grandparent = obj.grandparent
                c.save()

admin.site.register(Parent, ParentAdmin)

但是如果您想确保Child始终更新,无论谁执行了save(),您都可以

1.-覆盖模型的save()函数(但如果模型位于不同的文件中,这可能会产生循环依赖:

class Parent(models.Model):
    grandparent = models.ForeignKey(GrandParent, null=True, blank=True, default=None) 

    def save(self, *args, **kwargs):
        for c in self.child_set.all():
            if c.granparent != self.grandparent:
                c.grandparent = self.grandparent
                c.save()
        super(Parent, self).save(*args, **kwargs)

2.-为避免循环依赖,您可以使用信号来捕获保存并对其进行操作

from django.db.models.signals import post_save
from django.dispatch import receiver

class Child(models.Model):
    parent = models.ForeignKey(Parent, null=True, blank=True, default=None)
    grandparent = models.ForeignKey(GrandParent, null=True, blank=True, default=None)  

@receiver(post_save, sender=Parent)
def post_save_parent_callback(sender, **kwargs):
    parent = kwargs['instance']
    for c in parent.child_set.all():
        if c.granparent != parent.grandparent:
            c.grandparent = parent.grandparent
            c.save()

希望这有帮助。