Labs ICT
Pro Login

Form Validation

Custom validation and error handling.

Field-Level Validation

You can validate individual fields by defining clean_() methods on your form.


from django import forms

class RegistrationForm(forms.Form):
    username = forms.CharField(max_length=150)
    age = forms.IntegerField()

    def clean_age(self):
        age = self.cleaned_data.get('age')
        if age < 18:
            raise forms.ValidationError('You must be at least 18 years old.')
        return age
    

The method name must match clean_ followed by the field name. Always return the cleaned value.

Using ValidationError

The ValidationError class lets you raise errors with custom messages during validation.


from django.core.exceptions import ValidationError

def validate_even(value):
    if value % 2 != 0:
        raise ValidationError('Only even numbers are allowed.')

class NumberForm(forms.Form):
    number = forms.IntegerField(validators=[validate_even])
    

You can pass ValidationError to the validators argument of any form field for reusable validation logic.

Custom Validators

Custom validators are reusable functions that check a single value and raise ValidationError if invalid.


from django.core.validators import RegexValidator

phone_validator = RegexValidator(
    regex=r'^\+?1?\d{9,15}$',
    message='Enter a valid phone number.'
)

class ContactForm(forms.Form):
    phone = forms.CharField(validators=[phone_validator])
    

Custom validators can be shared across multiple forms. They run before the field's built-in validation.

Try it Yourself →

Form-Level Validation with clean()

The clean() method validates the entire form after individual fields are cleaned.


class OrderForm(forms.Form):
    product = forms.CharField()
    quantity = forms.IntegerField()
    discount_code = forms.CharField(required=False)

    def clean(self):
        cleaned_data = super().clean()
        product = cleaned_data.get('product')
        quantity = cleaned_data.get('quantity')
        if product == 'premium' and quantity > 10:
            raise forms.ValidationError('Premium products limited to 10 per order.')
        return cleaned_data
    

Use clean() when validation depends on multiple fields. Always call super().clean() and return the cleaned data.

Collecting Multiple Errors

You can collect multiple validation errors and display them all at once.


class MultiErrorForm(forms.Form):
    password = forms.CharField(widget=forms.PasswordInput)
    confirm_password = forms.CharField(widget=forms.PasswordInput)

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        confirm = cleaned_data.get('confirm_password')
        errors = []
        if password and confirm and password != confirm:
            errors.append(forms.ValidationError('Passwords do not match.'))
        if password and len(password) < 8:
            errors.append(forms.ValidationError('Password must be at least 8 characters.'))
        if errors:
            raise forms.ValidationError(errors)
        return cleaned_data
    

Passing a list of ValidationError instances lets you report all problems at once instead of stopping at the first error.