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)
Firstly, you shouldn't override
full_clean as you have done. From the django docs on full_clean:
This method calls
Model.validate_unique(), in that order and raises a
ValidationErrorthat has a
message_dictattribute containing errors from all three stages.
full_clean method already calls
clean, but by overriding it, you've prevented it calling the other two methods.
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.
clean method would work, but you can actually handle your example case in the model field itself. Define your
name = models.CharField(max_length=128)
blank option will default to False. If the field is blank, a
ValidationError will be raised when you run
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.
Capturing the pre-save signals on on my models ensured clean will be called automatically.
from django.db.models.signals import pre_save def validate_model(sender, **kwargs): if 'raw' in kwargs and not kwargs['raw']: kwargs['instance'].full_clean() pre_save.connect(validate_model, dispatch_uid='validate_models')