Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

People also ask

Is Clean called before save Django?

Note that full_clean() will NOT be called automatically when you call your model's save() method. You'll need to call it manually if you want to run model validation outside of a ModelForm. (This is for backwards compatibility.)

How do I save models in Django?

Creating objects To create an object, instantiate it using keyword arguments to the model class, then call save() to save it to the database. This performs an INSERT SQL statement behind the scenes. Django doesn't hit the database until you explicitly call save() . The save() method has no return value.

What does form Save Do Django?

form. save() purpose is to save related model to database, you are right. You're also right about set_password , for more info just read the docs. Django knows about model and all it's data, due to instance it's holding (in your case user ).

Can Django models have functions?

Model MethodsDjango's Model class comes with many built-in methods. We have already used some of them— save() , delete() , __str__() and others. Where manager methods add table-level functionality to Django's models, model methods add row-level functions that act on individual instances of the model.


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:

  • http://code.djangoproject.com/ticket/13100
  • http://groups.google.com/group/django-developers/browse_frm/thread/b888734b05878f87

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()

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)

Instead of inserting a piece of code that declares a receiver, we can use an app as INSTALLED_APPS section in settings.py

INSTALLED_APPS = [
    # ...
    'django_fullclean',
    # your apps here,
]

Before that, you may need to install django-fullclean using PyPI:

pip install django-fullclean

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()