In this tutorial, we will learn how to create custom model validators using Django.
Understanding The Problem
Django models come with their own built-in validations, that we put while creating models. However, often we require further validations on some fields. Such as the title length or age can't be lesser than a particular value or the coupon code should be in all caps.
In such scenarios building, a custom model validator is the most straightforward solution.
Note: If you want validation only limited to the admin interface then read this article instead - Displaying Custom Validation Exception in Django Admin
If your goal is to create custom model validations that will remain constant throughout the app including the admin site then this tutorial is for you.
Creating Custom Model Validation In Django
We will again use the blog project for this tutorial. Our goal is to create a validator that will not allow titles with less than 10 letters.
This is how our existing model looks.
models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="blog_posts")
status = models.IntegerField(choices=STATUS, default=0)
content = models.TextField()
class Meta:
ordering = ["-created_on"]
def __str__(self):
return self.title
To create custom model validators we need to create a clean()
method within our model class.
models.py
from django.db import models
from django.core.exceptions import ValidationError
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="blog_posts")
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
summary = models.CharField(max_length=500, null=True, blank=True)
class Meta:
ordering = ["-created_on"]
def __str__(self):
return self.title
def clean(self):
if not len(self.title) > 10:
raise ValidationError(
{'title': "Title should have at least 10 letters"})
The clean method will raise an exception when the condition is not met.
At this point, if you save the files and went to the admin site, and try to create a post with less title less than 10 letters you would receive the error message.
Even though the admin site invokes the method. The clean method is not invoked on save()
or create()
by default. So the best practice is to override the save method of the model and invoke the full_clean()
method that under the hood calls clean and other validation hooks.
models.py
from django.db import models
from django.core.exceptions import ValidationError
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="blog_posts")
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
summary = models.CharField(max_length=500, null=True, blank=True)
class Meta:
ordering = ["-created_on"]
def __str__(self):
return self.title
def clean(self):
if not len(self.title) > 10:
raise ValidationError(
{'title': "Title should have at least 10 letters"})
def save(self, *args, **kwargs):
self.full_clean()
return super().save(*args, **kwargs)
That's all!
Save the file, run the server and see the validators in action.