14.4 Validators: django/core/validators.py
A validator is a callable that is given one value and raises ValidationError when the value will not do. django/ holds the general ones: RegexValidator and the validators of domain names, URLs and email addresses, BaseValidator and the limits built on it, DecimalValidator, FileExtensionValidator, and ready-made ones such as validate_email.
A validator is given the value and nothing else, so a function of one argument serves as well as a class, and one validator serves form and model fields alike.
Each validator here raises with a code, which names the rule broken ("min_value"), and parameters, which fill the message’s placeholders. The message is filled only when it is read, so a field’s own message for the code, put in the validator’s place, can use the same parameters. The berth form’s tonnage, given one:
# harbour/fleet/forms.py
tonnage = forms.IntegerField(
min_value=1,
error_messages={"min_value": "%(value)s tons is below the limit of %(limit_value)s."},
)
>>> form = BerthForm({"ship": "heron", "tonnage": "0", "arrives": "2026-10-20"})
>>> form.errors.as_data()
{'tonnage': [ValidationError(['0 tons is below the limit of 1.'])]}
A validator is ordinarily made once, with its module, field class or field, and called many times (validate_image_file_extension makes a new one at each call): a form’s copy of its fields copies each list of validators but not the validators. It holds what it was made with, and nothing between calls.
Where validators are called
A form field’s Field (A form field: the base class) and a model field’s (Validating an instance) work alike: they skip an empty value, call every validator of the field, gather all their errors into one ValidationError, and put the field’s own message in place of a validator’s where the field has one for its code.
An empty value is one of the field’s empty_values, which both base classes copy from EMPTY_VALUES: None, "" and an empty list, tuple or dictionary. Whether a field may be empty is its own question; no validator is asked it.
A validator in a migration
Every validator class of the module is decorated with deconstructible, whose deconstruct returns the arguments an instance was made with, so that a migration can write a model field’s validator as a call that makes it again (Serializing values: serializer_factory and deconstruct).
RegexValidator
RegexValidator is the base of the pattern validators. Its class attributes RegexValidator, RegexValidator, RegexValidator, RegexValidator and RegexValidator are defaults that its arguments replace, so a subclass can be written by setting attributes alone, as the auth app’s username validators are. The pattern is wrapped by _lazy_re_compile in a SimpleLazyObject, and compiled when it is first used.
A call looks for the pattern anywhere in str(value), by re, and the value is invalid when it is not found or, with inverse_match, when it is. A pattern that must match the whole value anchors itself, as each RegexValidator the module makes does with "^" and "\Z".
Domain names, URLs and email addresses
DomainNameValidator, URLValidator and EmailValidator share one description of a host name, kept on DomainNameValidator: labels of 1 to 63 characters that neither begin nor end with a hyphen, then a top-level domain of letters or a punycode label, "xn--" and the rest. A letter may be any character from U+00A1 to U+FFFF, so bücher.example passes as it is written, and is not converted to punycode.
DomainNameValidator joins the parts when it is made, ASCII-only ones with accept_idna=False, which also refuses a value that is not ASCII. It refuses a value that is not a string or is over 255 characters long, and wants a top-level domain, so "localhost" fails.
URLValidator refuses, in order and each with its code ("invalid" by default), a value that is not a string or is longer than URLValidator (2,048, MAX_URL_LENGTH); that holds a tab, carriage return, newline or null; whose scheme, before "://" and lower-cased, is not in URLValidator (by default "http", "https", "ftp" and "ftps"); that urllib cannot split; that fails the pattern, which takes as host an IPv4 address, an IPv6 address in brackets, a host name or "localhost"; whose address in brackets validate_ipv6_address refuses; and whose host name is missing or longer than 253 characters, RFC 1034’s limit.
EmailValidator splits the address and checks its parts in methods a subclass may replace. EmailValidator refuses a value that is empty, has no "@" or is longer than 320 characters, and splits it at the last "@". EmailValidator has the user part checked by EmailValidator, as a dot-atom or a quoted string, and the domain by EmailValidator, which passes one in the allowlist (by default ["localhost"]), one that matches the host-name pattern without the final dot a URL may have, or an address in brackets that validate_ipv46_address accepts.
Limits: BaseValidator and its subclasses
BaseValidator compares a value with a limit. A call passes the value through BaseValidator, calls the limit if it is callable, and raises if BaseValidator of the two is true, with the parameters "limit_value", "show_value" (the cleaned value) and "value". In the base class clean returns the value and compare is a is not b. MaxValueValidator and MinValueValidator compare the value, and MaxLengthValidator and MinLengthValidator its length; their codes are "max_value", "min_value", "max_length" and "min_length".
StepValueValidator, code "step_size", wants a multiple of the limit, by math.remainder with a tolerance of 1e-9, so that 0.3 is a multiple of 0.1. Given an offset, it counts from there, and its message names the offset and the next two valid values. The form IntegerField makes one from step_size=, with min_value= as the offset.
Decimals, file extensions and null characters
DecimalValidator refuses an infinity or a NaN as "invalid", then too many digits, decimal places or digits before the point, as "max_digits", "max_decimal_places" and "max_whole_digits".
FileExtensionValidator refuses a file whose name’s suffix, lower-cased, is not among the allowed extensions; with none given, it allows all. validate_image_file_extension makes one at each call from the extensions Pillow registers; without Pillow that list is empty and every file is refused. The form ImageField has it by default.
ProhibitNullCharactersValidator refuses a value whose string holds a null character. Every form CharField has one.
The ready-made validators
django/core/validators.py ).| name | what it is |
|---|---|
validate_integer |
calls integer_, a RegexValidator for an optional minus and digits |
validate_slug, validate_ |
RegexValidator instances: ASCII letters, digits, "_" and "-"; or Unicode word characters and "-" |
validate_email |
an EmailValidator |
validate_ |
a Domain |
validate_, validate_, validate_ |
functions; the third tries the other two |
ip_ |
the list of those for "both", "ipv4" or "ipv6", for the IP address fields; ValueError for another |
int_ |
makes a RegexValidator for unsigned integers (signed, if asked) joined by a separator, "," by default, as validate_ is |