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

2πŸ‘

βœ…

I personally stay away from using the Admin pages once you need real business logic, but here is the answer:

If you only need to do this from the Admin pages, you can simply overwrite the Admin save function

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)

But if you would like to ensure the Child is always updated, regardless of who did the save(), you can

1.- Overwrite the model’s save() function (but this may create a circular dependency if your models are in different files:

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.- To avoid circular dependencies, you can use a signal to catch the save and act on it

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

Hope this helps.

πŸ‘€dkarchmer

Leave a comment