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

How to cascade an update in a one-to-many relationship?

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

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 管理区域中,我单击父记录 (P1) 并将其外键设置为祖父记录 (GP1)。

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

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

谢谢。

我个人不会在需要真正的业务逻辑时使用管理页面,但答案如下:

如果您只需要从管理页面执行此操作,您可以简单地覆盖管理保存功能

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()

希望这对您有所帮助。