Cancel saving model when using pre_save in django
Solution 1
See my another answer: https://stackoverflow.com/a/32431937/2544762
This case is normal, if we just want to prevent the save, throw an exception:
from django.db.models.signals import pre_save, post_save
@receiver(pre_save)
def pre_save_handler(sender, instance, *args, **kwargs):
# some case
if case_error:
raise Exception('OMG')
Solution 2
I'm not sure you can cancel the save only using the pre_save signal. But you can easily achieve this by overriding the save method:
def save(self):
if some_condition:
super(A, self).save()
else:
return # cancel the save
As mentioned by @Raptor, the caller won't know if the save was successful or not. If this is a requirement for you, take look at the other answer which forces the caller to deal with the "non-saving" case.
Solution 3
If the data's always coming from a Form and you have a straightforward test for whether or not the save should occur, send it through a validator. Note, though, that validators aren't called for save() calls originating on the backend. If you want those to be guarded as well, you can make a custom Field, say class PrimeNumberField(models.SmallIntegerField)
If you run your test and raise an exception in the to_python() method of that custom field, it will prevent the save. You can also hook into the validation of a specific field by overriding any of several other methods on the Field, Form, or Model.
Related videos on Youtube
![Alfred Huang](https://i.stack.imgur.com/RWHEP.png?s=256&g=1)
Comments
-
Alfred Huang about 2 years
I have a model:
class A(models.Model): number = models.IntegerField()
But when I call A.save(), I want to ensure that number is a prime (or other conditions), or the save instruction should be cancelled.
So how can I cancel the save instruction in the pre_save signal receiver?
@receiver(pre_save, sender=A) def save_only_for_prime_number(sender, instance, *args, **kwargs): # how can I cancel the save here?
-
AlvaroAV about 10 yearsYou have to overwrite the save function of the model, as @Sebastien said
-
-
Alfred Huang almost 9 yearsAfter a long time of practice, I found making a validator to restrict the field and always save before full_clean is a good architecture. You solution is the most enlightening.
-
Raptor over 7 yearsThis looks good however the caller has not idea that the save didn't work!
-
Alfred Huang about 7 yearsBe aware that if you use use update on a queryset, this hook is not triggered. e.g.
MyModel.objects.filter(some_case=1).update(someval=2)
Just prevent to use it. -
TheJKFever about 7 years@AlfredHuang, any way to raise an error when updating a queryset?
-
Alfred Huang about 7 years@TheJKFever AFAK, there is no straight forward solution, because queryset update will use one sql update on many rows. If you want to do so, traverse the queryset and update it one by one.
-
Vishal Rao over 5 yearsI think you could handle it with the post_save signal for updates since that's called on update. So a combination of the two signals would probably be the right answer here.
-
Silko over 5 yearsIs there a way to set the condition for saving in pre_save?
-
David Schumann over 4 yearsyes, instead of
return
an exception should be raised. -
Jayesh about 4 yearsI need to do this but raising exception breaks the flow. I don't want to break the flow. Also I can't override save method or use post_save.
-
justin over 3 yearsWhere's the best place to catch the exception raised in
pre_save
? I want to prevent the save, but don't want to result in a 500 error.