Is this the way to validate Django model fields?

django, django-models, python

Solution

Firstly, you shouldn't override `full_clean` as you have done. From the django docs on full_clean:

`Model.full_clean(exclude=None)` This method calls `Model.clean_fields()`, `Model.clean()`, and `Model.validate_unique()`, in that order and raises a `ValidationError` that has a `message_dict` attribute containing errors from all three stages.

So the `full_clean` method already calls `clean`, but by overriding it, you've prevented it calling the other two methods.

Secondly, calling `full_clean` in the `save` method is a trade off. Note that `full_clean` is already called when model forms are validated, e.g. in the Django admin. So if you call `full_clean` in the `save` method, then the method will run twice.

It's not usually expected for the save method to raise a validation error, somebody might call `save` and not catch the resulting error. However, I like that you call `full_clean` rather than doing the check in the save method itself - this approach allows model forms to catch the problem first.

Finally, your `clean` method would work, but you can actually handle your example case in the model field itself. Define your `CharField` as

name = models.CharField(max_length=128)

The `blank` option will default to False. If the field is blank, a `ValidationError` will be raised when you run `full_clean`. Putting `default=None` in your `CharField` doesn't do any harm, but it is a bit confusing when you don't actually allow `None` as a value.

Problem

As I understand it, when one creates a Django application, data is validated by the form before it's inserted into a model instance which is then written to the database. But if I want to create an additional layer of protection at the data model layer, is what I've done below the current "best practice?" I'm trying to ensure that a reviewer's name cannot be omitted nor be left blank. Should I be putting any custom validation in the 'clean' method as I've done here and then have 'save' call 'full_clean" which calls 'clean'? If not, what's the preferred method? Thanks. ``` class Reviewer(models.Model): name = models.CharField(max_length=128, default=None) def clean(self, *args, **kwargs): if self.name == '': raise ValidationError('Reviewer name cannot be blank') super(Reviewer, self).clean(*args, **kwargs) def full_clean(self, *args, **kwargs): return self.clean(*args, **kwargs) def save(self, *args, **kwargs): self.full_clean() super(Reviewer, self).save(*args, **kwargs) ```

Original source

Related problems