Reputation: 2710
I have a pre_save defined on MyModel which looks something like this:
@receiver(pre_save, sender=MyModel)
def _mymodel_pre_save(sender, instance, **kwargs):
if some_condition():
instance.somecolumn = 'eggs'
i.e. it expects to be able to modify some attribute(s) of a MyModel instance, and of course expects those changes to be persisted during the save() call. I believe this is rather typical use of a pre_save function. This works fine as long as the save() call does not specify update_fields.
I am wondering if there is any safe and sensible way to use update_fields in a save() call of a MyModel instance at this point. If I naively call:
myinstance = MyModel.objects.get(id=100)
myinstance.othercolumn = 'spam'
myinstance.save(update_fields=['othercolumn'])
The UPDATE statement generated will look like:
UPDATE "myapp_mymodel" SET "othercolumn" = 'spam' WHERE "myapp_mymodel"."id" = 100
missing the intended update of "somecolumn" from the pre_save. I guess this condition can be detected from inside the pre_save by looking at the update_fields which are made available to the pre_save function (as a frozenset), but I can't see any way for a pre_save to force its intended changes to be made when the caller has a more-restrictive set of update_fields, as in the example above. Or is there any workaround?
Upvotes: 5
Views: 2646
Reputation: 1796
A work-around is:
@receiver(pre_save, sender=MyModel)
def _mymodel_pre_save(sender, instance, **kwargs):
if some_condition():
instance.somecolumn = 'eggs'
instance.save()
Note the extra "instance.save()" call.
But you must ensure some_condition() is not True anymore after instance.somecolumn = 'eggs' has been executed. If not, it would result in a loop of save / pre-save / save / pre-save calls
Upvotes: 2