The Python Oracle

Why doesn't django's model.save() call full_clean()?

Become part of the top 3% of the developers by applying to Toptal https://topt.al/25cXVn

--

Music by Eric Matyas
https://www.soundimage.org
Track title: Hypnotic Orient Looping

--

Chapters
00:00 Question
01:05 Accepted answer (Score 64)
01:33 Answer 2 (Score 36)
02:01 Answer 3 (Score 21)
02:20 Answer 4 (Score 3)
02:50 Thank you

--

Full question
https://stackoverflow.com/questions/4441...

Question links:
[django's full clean doc]: http://docs.djangoproject.com/en/dev/ref...

Accepted answer links:
http://code.djangoproject.com/ticket/131...
http://groups.google.com/group/django-de...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #django #djangomodels #djangovalidation

#avk47



ACCEPTED ANSWER

Score 71


AFAIK, this is because of backwards compatibility. There are also problems with ModelForms with excluded fields, models with default values, pre_save() signals, etc.

Sources you might be intrested in:




ANSWER 2

Score 36


Because of the compatibility considering, the auto clean on save is not enabled in django kernel.

If we are starting a new project and want the default save method on Model could clean automatically, we can use the following signal to do clean before every model was saved.

from django.dispatch import receiver
from django.db.models.signals import pre_save, post_save

@receiver(pre_save)
def pre_save_handler(sender, instance, *args, **kwargs):
    instance.full_clean()



ANSWER 3

Score 24


The simplest way to call the full_clean method is just to override the save method in your model:

class YourModel(models.Model):
    ...  
    
    def save(self, *args, **kwargs):
        self.full_clean()
        return super(YourModel, self).save(*args, **kwargs)



ANSWER 4

Score 4


Commenting on @Alfred Huang's answer and coments on it. One might lock the pre_save hook down to an app by defining a list of classes in the current module (models.py) and checking against it in the pre_save hook:

CUSTOM_CLASSES = [obj for name, obj in
        inspect.getmembers(sys.modules[__name__])
        if inspect.isclass(obj)]

@receiver(pre_save)
def pre_save_handler(sender, instance, **kwargs):
    if type(instance) in CUSTOM_CLASSES:
        instance.full_clean()