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.
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.