Reusable Validators

+15 Mana ✨

Introduction

Create validator functions and classes that can be reused across multiple fields and forms.

Key Concepts

Validator Function: Callable that raises ValidationError.

Validator Class: Configurable validator with call.

Real World Context

In a CMS, the same profanity filter and file size check are needed on multiple forms. Write a validate_no_profanity() function once and attach it via validators=[].

Deep Dive

Simple Validator Function

python
from django.core.exceptions import ValidationError

def validate_no_profanity(value):
    bad_words = ['spam', 'scam', 'xxx']
    for word in bad_words:
        if word in value.lower():
            raise ValidationError(f'Content contains prohibited word: {word}')

class CommentForm(forms.Form):
    content = forms.CharField(validators=[validate_no_profanity])

Configurable Validator Class

python
class FileSizeValidator:
    def __init__(self, max_mb=5):
        self.max_mb = max_mb
        self.max_bytes = max_mb * 1024 * 1024
    
    def __call__(self, file):
        if file.size > self.max_bytes:
            raise ValidationError(f'File must be under {self.max_mb}MB')

class UploadForm(forms.Form):
    document = forms.FileField(validators=[FileSizeValidator(max_mb=10)])

Built-in Validators

python
from django.core.validators import (
    MinLengthValidator, MaxLengthValidator,
    MinValueValidator, MaxValueValidator,
    RegexValidator, EmailValidator,
)

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

Common Pitfalls

  1. Mutating the value inside a validator -- Validators should only check validity. Their return value is ignored.
  2. Using lambdas for validators -- Not serializable by Django migrations. Use a function or class.
  3. Not providing code in ValidationError -- Without it, errors cannot be customized.

Best Practices

  1. Prefer built-in validators -- RegexValidator, MinValueValidator, FileExtensionValidator cover common cases.
  2. Implement __eq__ and deconstruct -- Required for model field validators in migrations.

Summary

Validator functions are simplest. Validator classes allow configuration. Use built-in validators when possible.

✓ Completed