Built-in & Custom Validation
Django forms have built-in validation (required, max_length, email format) and support custom validation at the field level (clean_fieldname) and form level (clean). Validators are reusable functions that can be shared across forms and models.
20 min•By Priygop Team•Updated 2026
Validation Types
- Built-in: required, max_length, min_length, email format
- clean_fieldname() — Validate a single field
- clean() — Cross-field validation (compare passwords, etc.)
- validators=[func] — Reusable validator functions
- ValidationError — Raise for invalid data
- Form-level: clean() runs after all field-level validation
- Model-level: validators in model field definitions
Validation Example
Validation Example
# blog/forms.py
# from django import forms
# from django.core.validators import MinLengthValidator, RegexValidator
# from django.core.exceptions import ValidationError
# Reusable validator
# def validate_no_profanity(value):
# bad_words = ['spam', 'scam']
# for word in bad_words:
# if word in value.lower():
# raise ValidationError(f'Content contains inappropriate word: {word}')
# class RegistrationForm(forms.Form):
# username = forms.CharField(
# min_length=3, max_length=30,
# validators=[
# RegexValidator(
# regex=r'^[a-zA-Z0-9_]+$',
# message='Username can only contain letters, numbers, and underscores'
# )
# ]
# )
# email = forms.EmailField()
# password = forms.CharField(min_length=8, widget=forms.PasswordInput)
# confirm_password = forms.CharField(widget=forms.PasswordInput)
# bio = forms.CharField(
# required=False,
# validators=[validate_no_profanity]
# )
#
# # Field-level validation
# def clean_username(self):
# username = self.cleaned_data['username']
# if User.objects.filter(username=username).exists():
# raise ValidationError('Username already taken.')
# return username
#
# # Cross-field validation
# def clean(self):
# cleaned = super().clean()
# password = cleaned.get('password')
# confirm = cleaned.get('confirm_password')
# if password and confirm and password != confirm:
# raise ValidationError('Passwords do not match.')
# return cleanedTip
Tip
Use CreateView with form_class for custom forms, or model + fields for auto-generated forms. Both handle GET and POST.
Diagram
Loading diagram…
QuerySets are LAZY — no DB hit until evaluated.
Common Mistake
Warning
Forgetting to set model or form_class in CreateView. Without it, Django doesn't know what model/form to use.
Practice Task
Note
(1) Create a CreateView with ModelForm. (2) Override form_valid to set author. (3) Test with valid and invalid data.
Quick Quiz
Key Takeaways
- Django forms have built-in validation (required, max_length, email format) and support custom validation at the field level (clean_fieldname) and form level (clean).
- Built-in: required, max_length, min_length, email format
- clean_fieldname() — Validate a single field
- clean() — Cross-field validation (compare passwords, etc.)