Creating Custom Model Validation In Django

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.

Creating Custom Model Validation In DjangoThis 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.

Support Django Central

If you appreciate my work, or if it has helped you along your journey. It would mean a lot to me if you could write a message on my wall and share a cup of coffee (or tea) with me.
Buy Me a Coffee at ko-fi.com

Leave a Comment