Django Extensions is a comprehensive collection of custom extensions that enhance the Django web framework with additional management commands, utilities, and developer tools.
—
Django Extensions provides custom validation classes for field-level validation including control character prevention, whitespace validation, and hexadecimal string validation. These validators integrate seamlessly with Django's form and model validation system.
Validates that control characters like newlines, tabs, and other control characters are not present in the input, with optional whitelist support.
@deconstructible
class NoControlCharactersValidator:
message: str = "Control Characters like new lines or tabs are not allowed."
code: str = "no_control_characters"
whitelist: str | None = None
def __init__(self, message=None, code=None, whitelist=None):
"""
Validator that prevents control characters in input.
Parameters:
- message: Custom error message (optional)
- code: Custom error code (optional)
- whitelist: String of allowed control characters (optional)
"""
def __call__(self, value):
"""
Validate the input value.
Parameters:
- value: The value to validate
Raises:
- ValidationError: If control characters are found (excluding whitelist)
"""
def __eq__(self, other):
"""Check equality with another validator instance."""Usage examples:
from django.db import models
from django_extensions.validators import NoControlCharactersValidator
class CleanTextField(models.Model):
# Prevent all control characters
clean_text = models.TextField(
validators=[NoControlCharactersValidator()]
)
# Allow specific control characters (tabs)
text_with_tabs = models.TextField(
validators=[NoControlCharactersValidator(whitelist='\t')]
)
# Custom error message
strict_text = models.TextField(
validators=[NoControlCharactersValidator(
message="This field cannot contain control characters like newlines."
)]
)
# In forms
from django import forms
class CommentForm(forms.Form):
comment = forms.CharField(
widget=forms.Textarea,
validators=[NoControlCharactersValidator(
message="Comments cannot contain control characters.",
whitelist='\t' # Allow tabs but not newlines
)]
)
# Programmatic validation
validator = NoControlCharactersValidator()
try:
validator("Hello\nWorld") # Raises ValidationError
except ValidationError as e:
print(e.message) # "Control Characters like new lines or tabs are not allowed."
# With whitelist
validator_with_tabs = NoControlCharactersValidator(whitelist='\t')
validator_with_tabs("Hello\tWorld") # OK - tabs are whitelistedValidates that input does not have leading or trailing whitespace characters.
@deconstructible
class NoWhitespaceValidator:
message: str = "Leading and Trailing whitespaces are not allowed."
code: str = "no_whitespace"
def __init__(self, message=None, code=None, whitelist=None):
"""
Validator that prevents leading/trailing whitespace.
Parameters:
- message: Custom error message (optional)
- code: Custom error code (optional)
- whitelist: Not used (for consistency with other validators)
"""
def __call__(self, value):
"""
Validate the input value.
Parameters:
- value: The value to validate
Raises:
- ValidationError: If leading or trailing whitespace is found
"""
def __eq__(self, other):
"""Check equality with another validator instance."""Usage examples:
from django.db import models
from django_extensions.validators import NoWhitespaceValidator
class TrimmedField(models.Model):
# Ensure no leading/trailing whitespace
username = models.CharField(
max_length=50,
validators=[NoWhitespaceValidator()]
)
# Custom error message
api_key = models.CharField(
max_length=100,
validators=[NoWhitespaceValidator(
message="API keys cannot have leading or trailing spaces."
)]
)
# In forms
from django import forms
class UserRegistrationForm(forms.Form):
username = forms.CharField(
max_length=50,
validators=[NoWhitespaceValidator(
message="Username cannot start or end with spaces."
)]
)
# Programmatic validation
validator = NoWhitespaceValidator()
validator("username") # OK
validator(" username") # Raises ValidationError
validator("username ") # Raises ValidationError
validator(" username ") # Raises ValidationError
# Combining validators
class StrictUsernameField(models.CharField):
def __init__(self, *args, **kwargs):
kwargs.setdefault('validators', [])
kwargs['validators'].extend([
NoWhitespaceValidator(),
NoControlCharactersValidator()
])
super().__init__(*args, **kwargs)Validates that input contains only hexadecimal characters with configurable length constraints.
@deconstructible
class HexValidator:
messages: dict = {
'invalid': "Only a hex string is allowed.",
'length': "Invalid length. Must be %(length)d characters.",
'min_length': "Ensure that there are more than %(min)s characters.",
'max_length': "Ensure that there are no more than %(max)s characters."
}
code: str = "hex_only"
def __init__(
self,
length=None,
min_length=None,
max_length=None,
message=None,
code=None
):
"""
Validator for hexadecimal strings with length constraints.
Parameters:
- length: Exact length required (optional)
- min_length: Minimum length required (optional)
- max_length: Maximum length allowed (optional)
- message: Custom error message for invalid hex (optional)
- code: Custom error code (optional)
"""
def __call__(self, value):
"""
Validate the input value.
Parameters:
- value: The value to validate
Raises:
- ValidationError: If value is not valid hexadecimal or wrong length
"""
def __eq__(self, other):
"""Check equality with another validator instance."""Usage examples:
from django.db import models
from django_extensions.validators import HexValidator
class CryptoModel(models.Model):
# Validate hex string of any length
hex_data = models.CharField(
max_length=100,
validators=[HexValidator()]
)
# Validate hex string of exact length (e.g., MD5 hash)
md5_hash = models.CharField(
max_length=32,
validators=[HexValidator(length=32)]
)
# Validate hex string with min/max length
flexible_hex = models.CharField(
max_length=64,
validators=[HexValidator(min_length=8, max_length=64)]
)
# Color hex code (6 characters)
color_code = models.CharField(
max_length=6,
validators=[HexValidator(
length=6,
message="Please enter a valid 6-character hex color code."
)]
)
# Common use cases
class SecurityModel(models.Model):
# SHA-256 hash (64 hex characters)
sha256_hash = models.CharField(
max_length=64,
validators=[HexValidator(length=64)]
)
# API key (32 hex characters)
api_key = models.CharField(
max_length=32,
validators=[HexValidator(length=32)]
)
# Session token (variable length, 16-128 characters)
session_token = models.CharField(
max_length=128,
validators=[HexValidator(min_length=16, max_length=128)]
)
# In forms
from django import forms
class ColorForm(forms.Form):
background_color = forms.CharField(
max_length=6,
validators=[HexValidator(
length=6,
message="Enter a valid 6-digit hex color (e.g., FF0000)"
)],
widget=forms.TextInput(attrs={'placeholder': 'FF0000'})
)
# Programmatic validation
validator = HexValidator(length=8)
validator("DEADBEEF") # OK
validator("deadbeef") # OK (case insensitive)
validator("GGGGGGGG") # Raises ValidationError - invalid hex
validator("DEAD") # Raises ValidationError - wrong length
# Min/max length validation
range_validator = HexValidator(min_length=4, max_length=8)
range_validator("ABCD") # OK
range_validator("ABCDEF12") # OK
range_validator("ABC") # Raises ValidationError - too short
range_validator("ABCDEF123") # Raises ValidationError - too longValidators can be combined for comprehensive input validation:
from django.db import models
from django_extensions.validators import (
NoControlCharactersValidator,
NoWhitespaceValidator,
HexValidator
)
class SecureModel(models.Model):
# Username: no control characters, no leading/trailing whitespace
username = models.CharField(
max_length=50,
validators=[
NoControlCharactersValidator(),
NoWhitespaceValidator()
]
)
# API key: must be exactly 32 hex characters
api_key = models.CharField(
max_length=32,
validators=[
HexValidator(length=32),
NoWhitespaceValidator() # Extra safety
]
)
# Description: no control characters except newlines and tabs
description = models.TextField(
validators=[
NoControlCharactersValidator(whitelist='\n\t')
]
)
# Custom validator combinations
def create_secure_hex_validator(length):
"""Create a validator that ensures secure hex strings."""
return [
HexValidator(length=length),
NoWhitespaceValidator(),
NoControlCharactersValidator()
]
class CryptoHash(models.Model):
sha256 = models.CharField(
max_length=64,
validators=create_secure_hex_validator(64)
)from django.core.exceptions import ValidationError
from django_extensions.validators import HexValidator
# Custom validator with specific error codes
class StrictHexValidator(HexValidator):
def __init__(self, length=None, **kwargs):
super().__init__(length=length, **kwargs)
self.messages.update({
'invalid': 'Value must contain only hexadecimal characters (0-9, A-F).',
'length': f'Hex string must be exactly {length} characters long.'
})
# Usage in model
class HashModel(models.Model):
hash_value = models.CharField(
max_length=32,
validators=[StrictHexValidator(length=32)]
)
# Testing validators
def test_validators():
validator = NoControlCharactersValidator(
message="No control chars allowed!",
code="custom_control_char_error"
)
try:
validator("Hello\nWorld")
except ValidationError as e:
print(e.message) # "No control chars allowed!"
print(e.code) # "custom_control_char_error"from django import forms
from django_extensions.validators import (
NoControlCharactersValidator,
NoWhitespaceValidator,
HexValidator
)
class AdvancedForm(forms.Form):
username = forms.CharField(
validators=[
NoWhitespaceValidator(message="Username cannot have leading/trailing spaces"),
NoControlCharactersValidator(message="Username cannot contain control characters")
]
)
api_key = forms.CharField(
validators=[HexValidator(length=32, message="API key must be 32 hex characters")]
)
description = forms.CharField(
widget=forms.Textarea,
validators=[NoControlCharactersValidator(whitelist='\n\t')]
)
color = forms.CharField(
validators=[HexValidator(length=6)],
widget=forms.TextInput(attrs={
'class': 'color-picker',
'pattern': '[0-9A-Fa-f]{6}'
})
)Install with Tessl CLI
npx tessl i tessl/pypi-django-extensions