Understand clean() and clean_<fieldname>() in Django
In this tutorial we are going to focus on Form.clean() method and clean_fieldname() method , these methods help us validate data entered in forms by users.
we are going to use this app https://github.com/felix13/djangoclean for us to understand better.
lets say we have an app that takes in student information , for example, first name , last name and an image of the student.
We also want to validate the data entered by students and after thinking about it, we settle on the following rules.
- No student can have the same name as first name and last name, for example if you enter your first name as " Felix " and last name as " Felix " our app will throw an error.
- We are going to allow students to upload images that have the following extensions only (
'png'
,'jpg'
,'jpeg'
) and anything else will throw an error.
so if a user uploads a video with an extension of lets say .mp4
our app should reject it.
I know we have people with the same name as first name and last name, this is just for demonstration purposes.
Now lets lets dive into code and see how our app will look like, we will start with models.py
file
from django.db import models
class Document(models.Model):
first_name = models.CharField(max_length=255, blank=True)
last_name = models.CharField(max_length=255, blank=True)
image = models.FileField(upload_to='images/')
uploaded_at = models.DateTimeField(auto_now_add=True)
In the above code we have a Document
model which has fields for first_name, last_name, image and uploaded_at , Each attribute of the model represents a database field.
Lets look at our forms.py
file , it will look like this
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ('first_name', 'last_name', 'image', )
def clean_image(self):
IMAGE_FILE_TYPES = ['png', 'jpg', 'jpeg']
uploaded_image = self.cleaned_data.get("image", False)
extension = str(uploaded_image).split('.')[-1]
file_type = extension.lower()
if not uploaded_image:
raise ValidationError("please upload an Image") # handle empty image
if file_type not in IMAGE_FILE_TYPES:
raise ValidationError("File is not image.")
return uploaded_image
def clean(self):
cleaned_data = super().clean()
first_name = cleaned_data.get('first_name')
last_name = cleaned_data.get('last_name')
if first_name == last_name:
raise ValidationError( "First name and last name cannot be the same." )
Let me explain what is going on in our forms.py
file, first of all , we have two methods which are
clean_image()
clean()
Explanation
clean_image()
You might be asking yourself , why is our method called clean_image()
? , in Django, they generally call this method clean_<fieldname>()
where <fieldname>
is replaced with the name of the form field attribute .
In our example since we want to clean a specific field which is the image
field, we will replace the <fieldname>
with image
making it
clean_image()
.
Our method here does two things
- Check if image is uploaded, if not raise validation error.
- Check if image extension is of the type that is allowed
(
'png'
,'jpg'
,'jpeg'
) , if not raise validation error.
clean()
This is the form's clean()
method , do not confuse it with clean()
method on a field that we did above.
Django docs says
It’s important to keep the field and form difference clear when working out where to validate things. Fields are single data points, forms are a collection of fields.
read more on this here
This method is used in cleaning and validating fields that depend on each other. In our case we are checking if first_name == last_name
, if equal then we raise validation error.
Conclusion
clean_<fieldname>()
This is validation that is specific , we did write a clean method that operates on the image field.
clean()
Used in performing validation on more than one field at a time, In our example we did comparison of two fields by checking if first_name == last_name
.
Source code
You can find the source code of the app used in this example here
Resources
photo by Kari Shea on unsplash
Keep Learning
- Difference between Django forms.Form and forms.ModelForm
- Simple Pagination in Django
- Django Custom Error Pages