Django Form Validation
Ensuring data quality and security
✅ What is Form Validation?
Form validation checks user input for correctness and security. Django provides built-in validators and custom validation methods to ensure data meets your requirements before processing.
# forms.py - Basic validation
from django import forms
class SignupForm(forms.Form):
username = forms.CharField(min_length=3, max_length=20)
email = forms.EmailField()
age = forms.IntegerField(min_value=18)
Validation Types
Built-in Validators
Django's default validation
email = forms.EmailField()
Field Validation
Validate individual fields
def clean_username(self):
# validation logic
Form Validation
Validate multiple fields together
def clean(self):
# cross-field validation
Custom Validators
Reusable validation functions
validators=[custom_validator]
🔹 Built-in Field Validation
Django form fields include automatic validation based on field type and parameters. These validators check data format, length, and value ranges without extra code.
# forms.py
from django import forms
class RegistrationForm(forms.Form):
# Length validation
username = forms.CharField(
min_length=3,
max_length=20,
error_messages={
'min_length': 'Username must be at least 3 characters',
'max_length': 'Username cannot exceed 20 characters'
}
)
# Email format validation
email = forms.EmailField()
# Number range validation
age = forms.IntegerField(
min_value=18,
max_value=100
)
# Required field
terms = forms.BooleanField(
required=True,
error_messages={'required': 'You must accept terms'}
)
🔹 Custom Field Validation
Create clean_fieldname methods to add custom validation logic for specific fields. These methods run after built-in validators and can raise ValidationError for invalid data.
# forms.py
from django import forms
from django.core.exceptions import ValidationError
class UserForm(forms.Form):
username = forms.CharField(max_length=20)
password = forms.CharField(widget=forms.PasswordInput)
def clean_username(self):
username = self.cleaned_data.get('username')
# Check if username contains only letters and numbers
if not username.isalnum():
raise ValidationError(
'Username must contain only letters and numbers'
)
# Check if username is already taken
if User.objects.filter(username=username).exists():
raise ValidationError('Username already exists')
# Always return the cleaned data
return username
def clean_password(self):
password = self.cleaned_data.get('password')
if len(password) < 8:
raise ValidationError('Password must be at least 8 characters')
if not any(char.isdigit() for char in password):
raise ValidationError('Password must contain at least one number')
return password
🔹 Form-wide Validation
Use the clean method to validate multiple fields together. This is useful for checking relationships between fields or complex business logic requirements.
# forms.py
from django import forms
from django.core.exceptions import ValidationError
class PasswordChangeForm(forms.Form):
old_password = forms.CharField(widget=forms.PasswordInput)
new_password = forms.CharField(widget=forms.PasswordInput)
confirm_password = forms.CharField(widget=forms.PasswordInput)
def clean(self):
cleaned_data = super().clean()
new_password = cleaned_data.get('new_password')
confirm_password = cleaned_data.get('confirm_password')
old_password = cleaned_data.get('old_password')
# Check if passwords match
if new_password and confirm_password:
if new_password != confirm_password:
raise ValidationError('New passwords do not match')
# Check if new password is different from old
if old_password and new_password:
if old_password == new_password:
raise ValidationError(
'New password must be different from old password'
)
return cleaned_data
🔹 Custom Validators
Create reusable validator functions that can be applied to multiple fields. These functions take a value and raise ValidationError if validation fails.
# validators.py
from django.core.exceptions import ValidationError
import re
def validate_phone_number(value):
"""Validate phone number format"""
pattern = r'^\+?1?\d{9,15}$'
if not re.match(pattern, value):
raise ValidationError(
'Enter a valid phone number',
code='invalid_phone'
)
def validate_no_special_chars(value):
"""Check for special characters"""
if not value.isalnum():
raise ValidationError(
'Only letters and numbers allowed',
code='special_chars'
)
# forms.py
from django import forms
from .validators import validate_phone_number, validate_no_special_chars
class ContactForm(forms.Form):
name = forms.CharField(
validators=[validate_no_special_chars]
)
phone = forms.CharField(
validators=[validate_phone_number]
)
🔹 Displaying Validation Errors
Django automatically collects validation errors and makes them available in templates. Display errors next to fields or show all errors together.
<!-- template.html -->
<form method="post">
{% csrf_token %}
<!-- Show all errors at once -->
{% if form.errors %}
<div class="alert alert-danger">
<ul>
{% for field, errors in form.errors.items %}
{% for error in errors %}
<li>{{ field }}: {{ error }}</li>
{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
<!-- Show errors per field -->
<div>
{{ form.username.label_tag }}
{{ form.username }}
{% if form.username.errors %}
<span class="error">{{ form.username.errors }}</span>
{% endif %}
</div>
<button type="submit">Submit</button>
</form>