Support Our Site

To ensure we can continue delivering content and maintaining a free platform for all users, we kindly request that you disable your adblocker. Your contribution greatly supports our site's growth and development.

Creating Custom Model Validation In Django

3 min read

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.


DJANGO

Latest Articles

Latest from djangocentral

How to Use Subquery() in Django With Practical Examples

In the realm of web development, Django stands as a powerful and versatile framework for building robust applications. One of the key aspects of developing efficient and optimized web applications is handling database queries effectively. In this article…
Read more →

4 min read

DRF Serializer: Handling OrderedDict and Converting It to a Dictionary or JSON

In Django Rest Framework (DRF) tests, when you access serializer.data, you might encounter an OrderedDict instead of a regular dictionary. This behavior is intentional and reflects the design of DRF's serialization process.Understanding the Problem The u…
Read more →

3 min read

Django Rest Framework CheetSheet: Mastering API Development

Django Rest Framework (DRF) is a powerful toolkit that makes building robust and scalable web APIs with Django a breeze. Whether you're a seasoned Django developer or a newcomer, having a comprehensive cheat sheet at your disposal can be a game-changer. …
Read more →

5 min read

How to Perform NOT Queries in Django ORM

In Django, performing NOT queries allows you to exclude certain records from the query results based on specific conditions. The NOT operator, represented by the tilde (~) when used in conjunction with the Django ORM's Q object, helps you construct compl…
Read more →

3 min read