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

2019-01-04 18:49发布

I'm just curious if anyone knows if there's good reason why django's orm doesn't call 'full_clean' on a model unless it is being saved as part of a model form.

Note that full_clean() will not be called automatically when you call your model’s save() method. You’ll need to call it manually when you want to run one-step model validation for your own manually created models. django's full clean doc

(NOTE: quote updated for Django 1.6... previous django docs had a caveat about ModelForms as well.)

Are there good reasons why people wouldn't want this behavior? I'd think if you took the time to add validation to a model, you'd want that validation run every time the model is saved.

I know how to get everything to work properly, I'm just looking for an explanation.

5条回答
神经病院院长
2楼-- · 2019-01-04 19:04

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:

查看更多
可以哭但决不认输i
3楼-- · 2019-01-04 19:08

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

def save(self, *args, **kwargs):
    self.full_clean()
    return super(YourModel, self).save(*args, **kwargs)
查看更多
【Aperson】
4楼-- · 2019-01-04 19:18

If you have a model that you want to ensure has at least one FK relationship, and you don't want to use null=False because that requires setting a default FK (which would be garbage data), the best way I've come up with is to add custom .clean() and .save() methods. .clean() raises the validation error, and .save() calls the clean. This way the integrity is enforced both from forms and from other calling code, the command line, and tests. Without this, there is (AFAICT) no way to write a test that ensures that a model has a FK relation to a specifically chosen (not default) other model.

class Payer(models.Model):

    name = models.CharField(blank=True, max_length=100)
    # Nullable, but will enforce FK in clean/save:
    payer_group = models.ForeignKey(PayerGroup, null=True, blank=True,)

    def clean(self):
        # Ensure every Payer is in a PayerGroup (but only via forms)
        if not self.payer_group:
            raise ValidationError(
                {'payer_group': 'Each Payer must belong to a PayerGroup.'})

    def save(self, *args, **kwargs):
        self.full_clean()
        return super().save(*args, **kwargs)

    def __str__(self):
        return self.name
查看更多
Root(大扎)
5楼-- · 2019-01-04 19:20

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
查看更多
6楼-- · 2019-01-04 19:26

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()
查看更多
登录 后发表回答