4 min read

Validating Form Input With Django

Aug 12, 2020 9:26:56 AM

Let’s say I’m making a blogging web application using Python and the web framework, Django. I want users to be able to publish “Posts” on my blogging website.

When they enter that “Post” into some sort of input form that I have on my website, I want to check the “Post” before I save it to my database.

This is a common scenario for many Django developers. How do we validate form data before we save it to a database?

There’s two common ways to do it: Either validate the Model or validate the Form.

Django has Forms and Models. Very basically, Forms are where users input data on a web application, and Models and where I actually save my information in my program.

Let’s look first at how to validate the Model:

 

Validate the Model:

My Post model would look something like this, within my models.py file:


class Post(models.Model):
title = models.CharField(max_length=40)
content = models.CharField(max_length=4000)
slug = models.SlugField(max_length=40)
created_at = models.DateTimeField(editable=False)
updated_at = models.DateTimeField()
user = models.ForeignKey(
User,
null = True,
default = None,
on_delete = models.SET_DEFAULT,
)

Now, let’s say I want to validate the title field, so that all users’ Posts must have a title that is at least 5 characters long. Now, still within models.py I could add this function:


from django.core.exceptions import ValidationError

def min_validation(value):
if len(value) < 5:
raise ValidationError("{} is invalid, must have more than 5 characters". format(value))

This is a function to check if there’s 5 characters in any string. To use this function to validate my model, I could change my Post model by adding two methods, like this:


class Post(models.Model):
title = models.CharField(max_length=40)
content = models.CharField(max_length=4000)
slug = models.SlugField(max_length=40)
created_at = models.DateTimeField(editable=False)
updated_at = models.DateTimeField()
user = models.ForeignKey(
User,
null = True,
default = None,
on_delete = models.SET_DEFAULT,
)

def save(self, *args, **kwargs):
self.slug = slugify(self.title)
self.updated_at = timezone.now()
if not self.id:
self.created_at = timezone.now()
self.full_clean()
super(Post, self).save(*args, **kwargs)


def clean(self):
min_validation(self.title)

This new Post model has a save() method and a clean() method. You can see that within clean(), I use my min_validation() function. Now, whenever I save an object of type Post anywhere in my Django application, these functions will first check to see if the title is at least 5 characters.

Validate the Form:

Another way to tackle this problem is to validate the form input as soon as the user enters his/her data.

Within my forms.py file, I have a form that could look like this:


class PostForm(forms.ModelForm):

def __init__(self, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
self.fields["title"].validators.append(min_validation)


class Meta:
model = Post
fields = [
"title",
"content",
]
widgets = {
"content": Textarea(attrs={"cols": 50, "rows": 10}),
}

This is Django code that I could use to make a basic form in which users could input a Post title and content. You can see that in the form’s __init__() function, I’ve included the min_validation function. Note that I’d have to define this min_validation function elsewhere in forms.py, or I’d have to import it into forms.py if I want this to work.

With this strategy, I’ve added a custom validation function to the ‘title’ field of my Post form.

Summary

Django gives you a few options for defining custom validators in your models and forms. If you have form input that you’d like to check in some way, two options you have are to place your validators on the model or on the form. Both of these will produce the desired outcome. I hope these examples will help you out!

 
 

Liked what you read? Checkout Byte Academy's Software Development and Intro to Python courses.

 

Written by Jeff Maxim

Featured