Процесс валидации форм
Метод is_valid() является точкой входа в процесс валидации формы. Когда вы вызываете этот метод на экземпляре формы, тогда последовательно выполняются следующие шаги:
to_python():- Это первый шаг в процессе валидации.
- Метод преобразует входное значение в правильный Python-объект.
- Если преобразование невозможно, метод должен поднять
ValidationError. - Возвращаемое значение - это преобразованный объект.
- Например,
FloatFieldпреобразует входные данные в Python float, либо поднимаетValidationError.
validate():- Этот метод отвечает за валидацию, специфичную для данного поля.
- Он принимает уже преобразованное в правильный тип значение и может поднять
ValidationErrorв случае ошибки. - Метод не должен возвращать ничего и не должен изменять значение.
- Его следует переопределять, чтобы реализовать логику валидации, которую нельзя или не хочется помещать в валидатор.
run_validators():- Этот метод запускает все валидаторы, прикрепленные к полю, и объединяет все поднятые ошибки в единый
ValidationError. - Не рекомендуется переопределять этот метод.
- Этот метод запускает все валидаторы, прикрепленные к полю, и объединяет все поднятые ошибки в единый
clean():- Этот метод ответственен за последовательный вызов
to_python(),validate()иrun_validators(), а также за распространение поднятых ошибок. - Если любой из вызываемых методов поднимает
ValidationError, валидация прекращается и ошибка поднимается дальше. - Этот метод возвращает очищенные данные, которые затем помещаются в словарь
cleaned_dataформы.
- Этот метод ответственен за последовательный вызов
clean_<fieldname>():- Этот метод вызывается на подклассе формы, где
<fieldname>заменяется на имя атрибута поля формы. - Метод выполняет очистку и валидацию, специфичную для данного поля, независимо от типа поля.
- В этом методе нет параметров, вместо этого необходимо получать значение поля из
self.cleaned_data, помня, что это будет объект Python, а не изначальная строка, отправленная в форме. - Возвращаемое значение этого метода заменяет существующее значение в
cleaned_data, поэтому оно должно быть либо значением поля изcleaned_data(даже если метод его не изменял), либо новым очищенным значением.
- Этот метод вызывается на подклассе формы, где
В целом, эти методы выполняются последовательно для каждого поля формы, а затем вызывается метод clean()самой формы, независимо от того, были ли ошибки в предыдущих методах.
Сообщения об ошибках
Параметр error_messages поля формы Django предназначен для настройки пользовательских сообщений об ошибках, которые будут выводиться, если при валидации поля возникнет ошибка.
- По умолчанию, каждое поле формы имеет набор стандартных сообщений об ошибках, связанных с различными типами ошибок (например, “Обязательное поле”, “Введите действительный электронный адрес” и т.д.).
- Разработчик может переопределить эти стандартные сообщения об ошибках, передав в конструктор поля словарь
error_messages, где ключами будут коды ошибок, а значениями - пользовательские сообщения.
Пример:
from django import forms
class MyForm(forms.Form):
email = forms.EmailField(
error_messages={
"required": "Пожалуйста, введите ваш email-адрес.",
"invalid": "Введенный адрес электронной почты недействителен."
}
)В этом примере мы переопределили сообщения об ошибках для поля email. Теперь, если при валидации этого поля возникнет ошибка “required” или “invalid”, будут выведены наши пользовательские сообщения вместо стандартных.
Сообщения об ошибках могут включать в себя подстановочные значения, которые будут автоматически заменены соответствующими значениями во время формирования окончательного сообщения. Например:
class MyForm(forms.Form):
age = forms.IntegerField(
min_value=18,
error_messages={
"min_value": "Вы должны быть не моложе %(limit_value)s лет."
}
)В этом случае, если введенное значение будет меньше 18, будет выведено сообщение “Вы должны быть не моложе 18 лет.”
Встроенные валидаторы Django
В Django уже предусмотрена логика для некоторых типов валидации. Эти классы можно передавать в параметр validators поля формы, следующим образом
from django.core.validators import MinLengthValidator, MaxLengthValidator
slug = forms.SlugField(max_length=255, label="URL", **validators=[
MinLengthValidator(5),
MaxLengthValidator(100),
]**)Описание встроенных валидаторов
| Валидатор | Описание | Синтаксис | Параметры |
|---|---|---|---|
RegexValidator | Проверяет, что значение соответствует заданному регулярному выражению. | RegexValidator(regex=None, message=None, code=None, inverse_match=None, flags=0) | - regex: регулярное выражение в виде строки или пре-скомпилированного регулярного выражения- message: сообщение об ошибке- code: код ошибки- inverse_match: если True, валидатор поднимает ошибку, если совпадение найдено- flags: флаги для компиляции регулярного выражения |
EmailValidator | Проверяет, что значение выглядит как корректный email-адрес. | EmailValidator(message=None, code=None, allowlist=None) | - message: сообщение об ошибке- code: код ошибки- allowlist: список разрешенных доменов, для которых не применяется проверка |
URLValidator | Проверяет, что значение выглядит как корректный URL. | URLValidator(schemes=None, regex=None, message=None, code=None, max_length=2048) | - schemes: список разрешенных схем URL- regex: регулярное выражение для проверки URL- message: сообщение об ошибке- code: код ошибки- max_length: максимальная допустимая длина URL |
validate_email | Экземпляр EmailValidator без специальных настроек. | validate_email | (нет параметров) |
validate_slug | Экземпляр RegexValidator, проверяет, что значение состоит только из букв, цифр, подчеркиваний и дефисов. | validate_slug | (нет параметров) |
validate_unicode_slug | Экземпляр RegexValidator, проверяет, что значение состоит только из Юникод-букв, цифр, подчеркиваний и дефисов. | validate_unicode_slug | (нет параметров) |
validate_ipv4_address | Экземпляр RegexValidator, проверяет, что значение выглядит как корректный IPv4-адрес. | validate_ipv4_address | (нет параметров) |
validate_ipv6_address | Проверяет, что значение выглядит как корректный IPv6-адрес. | validate_ipv6_address | (нет параметров) |
validate_ipv46_address | Проверяет, что значение выглядит как корректный IPv4 или IPv6-адрес. | validate_ipv46_address | (нет параметров) |
validate_comma_separated_integer_list | Экземпляр RegexValidator, проверяет, что значение представляет собой список целых чисел, разделенных запятыми. | validate_comma_separated_integer_list | (нет параметров) |
int_list_validator | Экземпляр RegexValidator, проверяет, что значение представляет собой список целых чисел, разделенных заданным разделителем. | int_list_validator(sep=',', message=None, code='invalid', allow_negative=False) | - sep: разделитель в списке целых чисел- message: сообщение об ошибке- code: код ошибки- allow_negative: разрешать отрицательные числа |
MaxValueValidator | Поднимает ValidationError, если значение больше limit_value. | MaxValueValidator(limit_value, message=None) | - limit_value: максимально допустимое значение- message: сообщение об ошибке |
MinValueValidator | Поднимает ValidationError, если значение меньше limit_value. | MinValueValidator(limit_value, message=None) | - limit_value: минимально допустимое значение- message: сообщение об ошибке |
MaxLengthValidator | Поднимает ValidationError, если длина значения больше limit_value. | MaxLengthValidator(limit_value, message=None) | - limit_value: максимальная допустимая длина- message: сообщение об ошибке |
MinLengthValidator | Поднимает ValidationError, если длина значения меньше limit_value. | MinLengthValidator(limit_value, message=None) | - limit_value: минимальная допустимая длина- message: сообщение об ошибке |
DecimalValidator | Поднимает ValidationError при превышении ограничений на количество цифр и десятичных знаков. | DecimalValidator(max_digits, decimal_places) | - max_digits: максимальное количество цифр- decimal_places: максимальное количество десятичных знаков |
FileExtensionValidator | Поднимает ValidationError, если расширение файла не входит в список разрешенных. | FileExtensionValidator(allowed_extensions, message, code) | -allowed_extensions: список разрешенных расширений файлов- message: сообщение об ошибке- code: код ошибки |
validate_image_file_extension | Использует Pillow, чтобы убедиться, что value.name (value - файл) имеет допустимое расширение изображения. | validate_image_file_extension | (нет параметров) |
ProhibitNullCharactersValidator | Поднимает ValidationError, если значение содержит символы NULL. | ProhibitNullCharactersValidator(message=None, code=None) | - message: сообщение об ошибке- code: код ошибки |
StepValueValidator | Поднимает ValidationError, если значение не является кратным limit_value с учетом offset. | StepValueValidator(limit_value, message=None, offset=None) | - limit_value: шаг для допустимых значений- message: сообщение об ошибке- offset: смещение для проверки кратности к limit_value |
Кастомный валидатор в виде функции
-
Ипортируйте необходимые модули и определите функцию-валидатор, которая будет реализовывать нужную вам логику, например, проверять, что число является четным:
# validators.py from django.core.exceptions import ValidationError def validate_even(value): if value % 2 != 0: raise ValidationError(f"{value} is not an even number")- Функция принимает значение
valueи проверяет, что оно делится на 2 без остатка. - Если число не является четным, она поднимает
ValidationErrorс пользовательским сообщением об ошибке.
- Функция принимает значение
-
Импортируйте необходимые модули в forms.py и создайте форму с полем, использующим валидатор:
from django import forms from .validators import validate_even class MyForm(forms.Form): even_field = forms.IntegerField(validators=[validate_even])- Определяется поле формы
even_fieldтипаIntegerField. - В аргумент
validatorsпередается список, содержащий функцию-валидаторvalidate_even.
- Определяется поле формы
-
Используйте форму:
form = MyForm(data={'even_field': 7}) if form.is_valid(): # form.cleaned_data['even_field'] будет содержать только четные числа print(form.cleaned_data['even_field']) else: print(form.errors)- Создается экземпляр формы
MyFormс данными, содержащими нечетное число. - Вызывается метод
is_valid(), который автоматически запускает валидацию поляeven_fieldс помощьюvalidate_even. - Если значение не проходит валидацию, в
form.errorsбудут записаны ошибки. - Если валидация пройдена успешно,
form.cleaned_data['even_field']будет содержать только четное число.
- Создается экземпляр формы
Кастомный валидатор в виде класса
-
Импортируйте необходимые модули:
# validators.py from django.core.exceptions import ValidationError from django.utils.deconstruct import deconstructible -
Определите класс-валидатор
EvenNumberValidator:@deconstructible class EvenNumberValidator: code = 'not_even' default_message = "%(value)s is not an even number." def __init__(self, message=None): self.message = message or self.default_message def __call__(self, value): if value % 2 != 0: raise ValidationError( self.message, code=self.code, params={'value': value} )- Класс отмечен декоратором
@deconstructible, чтобы он мог корректно сериализоваться для системы миграций. - Определён атрибут
code, который будет использоваться в качестве кода ошибки. - Определён атрибут
default_messageс сообщением об ошибке по умолчанию. - В
__init__()принимается необязательный аргументmessage, который переопределяет сообщение об ошибке. - Метод
__call__()реализует логику проверки: если значениеvalueне является чётным, поднимаетсяValidationErrorс соответствующим сообщением и кодом ошибки.
- Класс отмечен декоратором
-
Использование
EvenNumberValidatorв форме или модели:from django import forms from .validators import EvenNumberValidator class MyForm(forms.Form): even_field = forms.IntegerField(validators=[EvenNumberValidator()])- Импортируем определённый ранее класс-валидатор
EvenNumberValidator. - В
MyFormполеeven_fieldтипаIntegerFieldиспользуетEvenNumberValidatorв качестве валидатора.
- Импортируем определённый ранее класс-валидатор
Метод clean_field в классе формы
Создание кастомного метода clean_even_field() позволяет реализовать дополнительную логику очистки и валидации для конкретного поля формы, не затрагивая общую логику валидации. Это полезно, когда необходимо выполнить сложные проверки, выходящие за рамки возможностей стандартных валидаторов.
-
Определение класса формы с кастомным методом очистки:
from django import forms from django.core.exceptions import ValidationError class MyForm(forms.Form): even_field = forms.IntegerField() **def clean_even_field(self): even_field = self.cleaned_data.get('even_field') if even_field % 2 != 0: raise ValidationError( "The value for even_field must be an even number." ) return even_field** -
Логика метода
clean_even_field():- Метод получает значение
even_fieldизself.cleaned_data, которое было очищено стандартными методами очистки формы. - Если значение не является чётным, метод поднимает
ValidationErrorс сообщением об ошибке. - Если всё проверки пройдены успешно, метод возвращает очищенное значение
even_field.
- Метод получает значение
〰〰〰 𓆝 𓆟 𓆞 𓆝 𓆟 𓆝 𓆟 𓆞 〰〰〰