1

I have a model, let's save A, the definition is as below:

class A(models.Model):
   name = models.CharField('name', max_length=10)
   enabled = models.BooleanField('enabled', default=False)
   field1 = models.CharField('field1', max_length=10)
   field2 = models.CharField('field2', max_length=10)
   field3 = models.CharField('field3', max_length=10)
   parent = models.ForeignKey('self', null=True, blank=True) # hierarchy

and some object instances of this model, a, b, c, d. the hierarchy is represented by the parent field.

a 
|-- b
    |-- c
    |-- d

So, what I need to do is, when b.enabled change from False to True, or vice versa, I need to update c.enabled and d.enabled to value: b.enabled.

That's say, I need to broadcast the change to the children instances when the parent's enabled field was changed.

For performance consideration, I only need to broadcast the changes when enabled field is really changed. And don't want to always update the child instance whenever the parent is save, e.g. only updating field1 or field2.

So, do anyone knows, what is the best way to implement this logic? Thanks in advance.

Enix
  • 4,415
  • 1
  • 24
  • 37

2 Answers2

1

In short — no. But you can do it manually overloading the save method.

class B(models.Model):

    ...

    def save(self, *args, **kwargs):
        if self.pk is not None:
            original = B.objects.get(pk=self.pk)
            if original.enabled != self.enabled:
                C.enabled = self.enabled
                C.save()
                D.enabled = self.enabled
                D.save()
        super(B, self).save(*args, **kwargs)

 

Ledorub
  • 354
  • 3
  • 9
Andrey Shipilov
  • 1,986
  • 12
  • 14
  • hmm. I know this is a way to do this, but it need to execute query every time the model save. I have found this post related to this topic. http://stackoverflow.com/questions/23361057/django-comparing-old-and-new-field-value-before-saving. I think implement this logic in ModelForm level will be better than doing this in Model level. Anyway, thank you for you answer. – Enix Oct 14 '16 at 04:34
  • Do it in a transaction and it will execute all queries in a single transaction. Nothing wrong with that. – Andrey Shipilov Oct 14 '16 at 04:36
1

The best way to do this is using django signals https://docs.djangoproject.com/es/1.10/ref/signals/

You will call the method change_status when your model call the method save()

from django.db.models.signals import pre_save

def change_status(sender, instance, **kwargs):
    # instance object is the model that you have called the method save
    a = A.objects.get(id=instance.id) # or B or C model
    if instance.enable:
        a.enable = False
        # my code.....

pre_save.connect(change_status, sender=A) 
# sender is the model that will be called every time you call the method save

And That's it Remember that the object instance is your model before be changed, so if you have a.enable=True and call the method save() in change_status signal you can make a query without this change of a.enable=True intance.enable >> True, a.enable >> False because a is not saved yet.

Pablo Alejandro
  • 591
  • 2
  • 10
  • 19
  • yup, this is another way to capture the changes, but still need to query the object whenever the object is save. – Enix Oct 15 '16 at 02:39
  • No with django signal, you will implement the method chage_status (in this case) only in one function (in this signal), whenever you do A.save() this will call the function, and you haven't to do the same process in each case that you'll change the status, the method do the process and that's it, what do you don't understand? or who do not understand is me? – Pablo Alejandro Oct 15 '16 at 02:47