Background workers and overriding save method on Django models

360 Views Asked by At

I have a long-running process that depends on model fields.

Let's say I have a model that looks like this

class Client(models.Model):
    input_data = models.CharField(max_length=100)

    # The field that will be computed in the background task
    computed_data = models.CharField(max_length=100, null=True, blank=True)

I want to trigger a background task every time this model is updated, but the problem is I also need to call the save method after the background task updates the instance.

It's roughly looking something like this.

def a_long_running_background_task(instance):
    input_data = instance.input_data # Reading the model input data
    
    # Updating the output_data field using the input data from the model instance    
    instance.output_data = input_data.title()

    # To make sure the changes apply to the database we need to call the save method
    instance.save()

The problem with this code is that it would cause an infinite loop, because I'm calling the background task on the save method, and I'm calling the save method in the background task.

And I kept getting this error

RecursionError: maximum recursion depth exceeded while calling a Python object

After I researched this problem, I found a solution which suggests using the post_save signal, with the created attribute, and then would check if the instance is created, then would execute the task, if it's just updated, I would skip it because this means it's calling the save from the background worker.

The signal looked something like this:

@receiver(post_save, sender=Client)
def handle_new_client(sender, instance, created, **kwargs):
    if created:
        a_long_running_task(instance)

The problem now is, I want to have an update feature, and I would like the background task to trigger when updating the model, but it currently only triggers when creating the object.

I have one solution in mind, but I'm not sure how to implement it or if it would work, which is to split the computed fields from the input fields into two different models.

Any help is really appreciated.

1

There are 1 best solutions below

0
On BEST ANSWER

One option is to use bulk_update to update instances in your background task. This function won't call the model's save method and won't emit any signals, eliminating any recursion problem.