0

What is the most proper way to trigger update of related models, when one of the fields of parent model is changed? I have this set of models:

class ActivityObject(models.Model):
    is_deleted = models.BooleanField(default=False)

class ActivityJob(models.Model):
    activity_object = models.ForeignKey(
        ActivityObject,
        related_name='activity_jobs',
    )
    is_deleted = models.BooleanField(default=False)

so if I set ActivityObject.is_deleted = True on some instance all I want is that all related instances of ActivityJob also changed field is_deleted to True. Thanks in advance.

Compadre
  • 815
  • 1
  • 10
  • 18

2 Answers2

1

Overriding save() will work:

class ActivityObject(models.Model):
    is_deleted = models.BooleanField(default=False)

    def save(self, *args, **kwargs):
        super(ActivityObject, self).save(args, kwargs)
        if self.is_deleted:
            for job in self.activity_jobs:
                job.is_deleted = True
                job.save()

Just guessing here, but if the real purpose of this is to delete ActivityJobs when related ActivityObjects are deleted, then you can just go ahead and delete the ActivityObject. Django's default behavior will remove all the ActivityJobs connected to it.

If you want to perform some other action when deleting, use Django's pre_delete or post_delete signals, which will call a function you define before/after deleting objects of the type you specify.

EDIT: if you ever use update() on querysets dealing with ActivityObject and changing is_deleted, you can either ensure that you perform a corresponding update() on ActivityJob, or you can override ActivityObject's queryset functionality like this to make it happen automatically.

Community
  • 1
  • 1
Yash Tewari
  • 760
  • 1
  • 6
  • 19
  • What if save() is never called? – Brian Jul 06 '16 at 14:15
  • @Brian Can you provide an example where the database table for `ActivityObject` is changed without `save()` being called? – Yash Tewari Jul 06 '16 at 14:16
  • @Yash Tewari I think this is the most suitable solution in my case, thx – Compadre Jul 06 '16 at 14:56
  • @YashTewari `save()` is never called if `update()` is used. – Brian Jul 06 '16 at 18:43
  • That's right. As I understand it, since `update()` is used to perform changes on `querysets`, it is essentially a way to silently set values across the database. It doesn't trigger any signals, and it obviously doesn't use any `save()` overrides, so anybody using `update()` will in any case have to account for these things. Any time I use `update()` I have to ensure that it is accompanied by other actions which leave the database in a desirable state. I'll include this in the answer, thanks. – Yash Tewari Jul 06 '16 at 19:15
0

You can use Django signals' pre_delete or post_delete. More details and examples are available in the Django Signals documentation.

Siva Arunachalam
  • 7,582
  • 15
  • 79
  • 132
  • And can i wrap the whole thing with signals kitchen by @transaction.atomic decorator? Because in the upper answer I can wrap the whole `save` method and feel save if the parent object will be changed and related objects won't be changed for some reason. – Compadre Jul 06 '16 at 14:34
  • Thanks for this answer, and I understand that this solution is more flexible in many ways, but it is also much more complicated, including outer dependencies. If I ever need this kind of flexibility, I will use your way of solving that kind of issue. Thanks for spending time on answers :) – Compadre Jul 06 '16 at 14:54