Search code examples
djangodjango-modelsdjango-viewsmany-to-many

Update automatically a specific field in Django model when saving other many-to-many related model


How can I update a field of a model automatically when saving an instance of a related model? I need to solve this scenario:

class First(models.Model):
    name = models.CharField(max_length=100)
    assigned = models.BooleanField(default=False)

class Second(models.Model):
    some_attribute = models.CharField(max_length=100)
    firsts = models.ManyToManyField(First)

So, every time I create a Second instance I want to automatically update the 'assigned' attribute for every related object of First model and change it to True.

For simplification I am not saying that I have this models in different apps in the same project, I guess this is not so relevant, I just need the basics of it.

I am trying to override the save method of Second but having trouble to iterate through the related objects:

def save(self, *args, **kwargs):
    super(Second, self).save(*args, **kwargs) # Call the "real" save() method.
    items = self.firsts
    for item in items:
        item.assigned = True
        item.save()

I am also trying to avoid Signals since this sounds like and advance topic and I'm a beginner programmer and I intuit there should be a simpler way to do this. 'First' objects are created in a CreateView for that model; inline formsets are not needed.

Thanks for your help.


Solution

  • The save method of the Second model is not the right place to do what you need, because related objects are not yet updated at this time. You should update your First model after you save your Second model, for instance from the save method of the form used to create or update the Second instance.

    In the Second model:

    def update_firsts(self):
        items = self.firsts.all()
        for item in items:
            item.assigned = True
            item.save()
    

    In the form:

    def save(self, *args, **kwargs):
        instance = super(SecondForm, self).save(*args, **kwargs)
        instance.update_firsts()
        return instance