Validation error value is not valid перевод

Перевод контекст "value is not valid" c английский на русский от Reverso Context: MC3013: SynchronousMode property value is not valid. Valid values are Async and Sync.


На основании Вашего запроса эти примеры могут содержать грубую лексику.


На основании Вашего запроса эти примеры могут содержать разговорную лексику.

недопустимое значение

Значение не является допустимым


MC3013: SynchronousMode property value is not valid. Valid values are Async and Sync.



MC3013: недопустимое значение свойства SynchronousMode. Разрешены значения Async и Sync.


Internal table type value is not valid. This is an internally inconsistent condition.



Недопустимое значение типа внутренней таблицы. Это внутренне несогласованное состояние.


» value is not valid because it contains no animations.


Cannot open package because FileMode or FileAccess value is not valid for the stream.


» KeyTime value is not valid for key frame at index of this’ ‘ because it is greater than animation’s Duration value ».



Значение KeyTime не является допустимым для опорного кадра, соответствующего индексу для этого, так как оно больше, чем значение Duration для анимации.


» value is not valid because VisualTriggers do not support TemplateBinding.


The specified variable value is not valid for the selected variable type:


SeekOrigin value is not valid. Only SeekOrigin.Begin and SeekOrigin.Current are valid.



Недопустимое значение SeekOrigin. Допустимыми являются только значения SeekOrigin.Begin и SeekOrigin.Current.


The required’ ‘ attribute value is not valid.


The log file size value is not valid.


The HandoffBehavior value is not valid.


Value is not valid for the specified GUID.


Localization comment value is not valid for target property’ ‘ in string ».


» value is not valid. It must contain one, two, or four delimited Lengths.



Недопустимое значение. Оно должно содержать одно, два или четыре значения Length с разделителями.

Ничего не найдено для этого значения.

Результатов: 14. Точных совпадений: 14. Затраченное время: 38 мс

Предложения с «not valid»

They are not valid excuses for failing to do the right thing for our children, which is to start middle and high schools no earlier than 8:30am.

Это не веские причины отказаться от правильных идей, от которых выиграют наши дети, а именно от начала занятий в школах не ранее 8:30 утра.

Therefore, the reference to the 1992-1994 period was not valid .

Поэтому ссылка на период 1992 — 1994 годов ничем не обоснована.

The offer made to Lebanon is not valid .

Предлагаемый Ливану вариант не имеет силы.

A late objection, even if it was not valid , was always an objection.

Последующее возражение, даже если оно не действительно, всегда остается возражением.

Thus, the complaints made about the Myanmar Citizenship Law are not valid .

Таким образом, жалобы в отношении Закона о гражданстве Мьянмы не являются обоснованными.

Any religious or customary marriage which did not comply with the Marriage Act’s provisions was not valid .

Любой религиозный или традиционный брак, который не соответствует положениям Закона о браке, является недействительным .

SeekOrigin value is not valid . Only SeekOrigin.Begin and SeekOrigin.Current are valid .

Недопустимое значение SeekOrigin. Допустимыми являются только значения SeekOrigin.Begin и SeekOrigin.Current.

The specified property is not valid . Verify the type of the argument.

Указанное свойство недопустимо. Проверьте тип аргумента.

The file name property is not valid . The file name is a device or contains invalid characters.

Недопустимое свойство имени файла. Имя файла является именем устройства или содержит недопустимые символы.

The WSDL binding named is not valid because an operation binding doesn’t have a name specified.

Привязка WSDL с именем недопустима, так как для привязки операции не указано имя.

The requested TextDecorationCollection string is not valid : ».

Запрошенная строка TextDecorationCollection не является допустимой:.

Template can have only a single root element.’ ‘ is not valid .

Template может иметь только один корневой элемент. не является допустимым.

Attribute in ‘item’ not valid ; ‘repeat’ expected.

Недопустимый атрибут в элементе item; ожидается repeat.

Rule reference not valid . Must specify ‘uri’ or ‘special’.

Недопустимая ссылка на правило. Необходимо указать uri или special.

Zero-length TextRange is not valid for this processor.

Значение TextRange нулевой длины является недопустимым для данного обработчика.

Specified ContentPosition is not valid for this element.

Указанное значение ContentPosition не подходит для данного элемента.

Token is not valid because it is more than 250 characters.

Маркер является недействительным , поскольку содержит более 250 знаков.

Value is not valid for the specified GUID.

Значение не является допустимым для указанного GUID.

Default value for’ ‘ property is not valid because ValidateValueCallback failed.

Значение по умолчанию свойства не является допустимым, так как произошел сбой вызова ValidateValueCallback .

Layout information on TextView is not valid . Must call Validate before calling this method.

Недопустимые сведения о макете для TextView. Перед вызовом данного метода необходимо вызвать Validate .

Object metadata stream in the package is corrupt and the content is not valid .

Поток метаданных объекта в пакете поврежден, имеется недопустимое содержимое.

Internal table type value is not valid . This is an internally inconsistent condition.

Недопустимое значение типа внутренней таблицы. Это внутренне несогласованное состояние.

ClipToBounds is not valid for Window.

Значение ClipToBounds не является допустимым для Window.

Parameter and value pair is not valid . Expected form is parameter=value.

Неверная пара параметра и значения. Ожидается формат параметр=значение.

Cannot open package because FileMode or FileAccess value is not valid for the stream.

Не удается открыть пакет, так как значение FileMode или FileAccess не является допустимым для потока.

Locator part is not valid . Missing or malformed name/value pair: ».

Недопустимая часть локатора. Отсутствует или неверно сформирована пара имя — значение:.

Override tag is not valid per the schema. Verify that attributes are correct.

Переопределяющий тег является недопустимым согласно данной схеме. Проверьте правильность атрибутов.

Markup extensions are not allowed for Uid or Name property values, so’ ‘ is not valid .

Для значений свойств Uid или Name не допускаются расширения разметки, поэтому не является допустимым значением.

DataObject or data is not valid for conversion to OLE data.

DataObject или данные являются недопустимыми для преобразования в данные OLE.

ContentType string is not valid . Expected format is type/subtype.

Недопустимая строка ContentType. Ожидаемый формат: тип/подтип.

Character offset is not valid in document with characters.

Смещение символов недопустимо в документе с символами.

Number of samples in data block not valid .

Недопустимое число примеров в блоке данных.

Types tag has attributes not valid per the schema.

Тег типов имеет недопустимые атрибуты, согласно схеме.

The digital signature is not valid . The contents of the package have been modified.

Недействительная цифровая подпись. Содержимое пакета было изменено.

The key collection includes entry that is not valid . It must be an IBamlDictionaryKey.

Семейство ключей включает недопустимую запись. Требуется IBamlDictionaryKey.

The key decrypted from the file header is not valid .

Недопустимый ключ, дешифрованный из заголовка файла.

The defendant argued that the document was not valid as it was not signed.

Ответчик считает, что документ недействителен , так как в документе отсутствует его подпись.

Hence, the observer’s allegation that the draft law was not open for public comment was not valid .

Следовательно, утверждение наблюдателя о том, что общественности не была предоставлена возможность высказать замечания по законопроекту, лишено оснований.

The version number in the package is not valid . The version number cannot be greater than current version number.

Недопустимый номер версии в пакете. Номер версии не может быть больше номера текущей версии.

The configuration file loaded, but is not valid . The file is not formatted correctly, may be missing an element, or may be damaged.

Файл конфигурации загружен, но является недопустимым. Файл имеет неправильный формат, возможно, содержит отсутствующий элемент или поврежден.

Either the source object or the destination object is not valid .

Неверно заданный исходный или целевой объект.

The binary encoder session is not valid . There was an error decoding a previous message.

Недопустимый сеанс двоичного кодировщика. Ошибка декодирования предыдущего сообщения.

Invalid Audio header info. Cannot calculate data block size because blockAlign or metadata size not valid .

Недопустимые сведения заголовка звука. Не удается вычислить размер блока данных из — за недопустимого размера blockAlign или метаданных.

The address in the From line is malformed. It is either missing the symbol or is not valid .

Некорректный адрес в строке От. Отсутствует знак или адрес недопустим.

The object name is not valid . The name cannot be empty.

Недопустимое имя объекта. Имя не может быть пустым.

If you select a ship or receipt date that is not valid , the Simulate delivery dates form is displayed so that you can select alternative dates.

При выборе недопустимой даты отгрузки или поступления будет открыта форма Моделирование даты поставки, в которой можно выбрать альтернативные даты.

The email address or password you entered is not valid .

Введенный адрес электронной почты или пароль недействителен .

The counter-argument — that any sell-off or failure by China to continue to buy US government securities would hurt China as much as America — is not valid .

Встречный довод о том, что любая распродажа и прекращение дальнейшего приобретения Китаем государственных ценных бумаг США повредит Китаю так же сильно, как Америке, уже не является убедительным.

They are not valid for Cash, Cheque, ATM, or any other method of funds transfer.

Они не применимы к операциям с наличными, чеками, банкоматами или для любых других способов перевода средств.

It seems, then, that the proceedings in support of survival of firms permit Mexican law are not valid in the land of stars and stripes, contrary to international conventions.

Кажется, что процедуры в поддержку выживания фирм, которые дозволены мексиканскими законами, не являются действительными в стране полос и звезд, в противоречии с международными соглашениями.

Yes, and they’re not valid until they bear my signature and my seal.

Да, но к сожалению, без моей подписи оно недействительно .

I feel that since google links are often not valid , they should be discouraged.

Я считаю, что, поскольку ссылки google часто не являются действительными, они должны быть обескуражены.

A Schengen visa, even one issued by France, is not valid for these territories.

Шенгенская виза, даже выданная Францией, не действительна для этих территорий.

For small values of the shape parameter, the algorithms are often not valid .

При малых значениях параметра shape алгоритмы часто оказываются неверными.

Self-promotion, autobiography, product placement and most paid material are not valid routes to an encyclopedia article.

Самореклама, автобиография, продакт — плейсмент и большинство платных материалов не являются допустимыми маршрутами к энциклопедической статье.

Out of state permits not valid in Connecticut, but non-residents may apply for a Connecticut non-resident carry permit through the mail.

Внегосударственные разрешения не действительны в Коннектикуте,но нерезиденты могут подать заявку на получение внегосударственного разрешения по почте.

Some European countries require adults to carry proof of identity at all times, but a driving permit is not valid for identification in every European country.

Некоторые европейские страны требуют от взрослых постоянно иметь при себе удостоверение личности, но водительское удостоверение не является действительным для идентификации в каждой европейской стране.

Single Journey fare are not valid for transfers.

Для трансферов не действует единый тариф проезда.

If animal is not valid , I suggest to remove all animal-based National personification since it is about person.

Если животное не является действительным, я предлагаю удалить всю основанную на животных национальную персонификацию, так как речь идет о человеке.

This, however, implies that AaB does not entail AiB, and some of the syllogisms mentioned above are not valid when there are no A’s.

Это, однако, подразумевает, что AaB не влечет за собой AiB, и некоторые из силлогизмов, упомянутых выше, не являются действительными, когда нет никаких а.

Валидация форм и полей¶

Валидация формы происходит при очистке данных. Если вы хотите настроить этот процесс, есть различные места для внесения изменений, каждое из которых служит для разных целей. В процессе обработки формы выполняются три типа методов очистки. Обычно они выполняются, когда вы вызываете метод is_valid() на форме. Есть и другие вещи, которые также могут вызвать очистку и проверку (обращение к атрибуту errors или прямой вызов full_clean()), но обычно они не нужны.

В общем, любой метод очистки может поднять ValidationError, если есть проблема с данными, которые он обрабатывает, передавая соответствующую информацию конструктору ValidationError. See below для лучшей практики поднятия ValidationError. Если не поднимается ValidationError, метод должен вернуть очищенные (нормализованные) данные в виде объекта Python.

Большинство валидаций можно выполнить с помощью validators — помощников, которые можно использовать повторно. Валидаторы — это функции (или callables), которые принимают один аргумент и вызывают ValidationError при недопустимом вводе. Валидаторы запускаются после вызова методов to_python и validate поля.

Валидация формы разбита на несколько этапов, которые можно настроить или отменить:

  • Метод to_python() на Field является первым шагом в каждой валидации. Он преобразует значение к правильному типу данных и выдает сообщение ValidationError, если это невозможно. Этот метод принимает необработанное значение от виджета и возвращает преобразованное значение. Например, FloatField превратит данные в Python float или выдаст ValidationError.

  • Метод validate() на Field обрабатывает специфическую для поля валидацию, которая не подходит для валидатора. Он принимает значение, которое было приведено к правильному типу данных, и при любой ошибке выдает сообщение ValidationError. Этот метод ничего не возвращает и не должен изменять значение. Вы должны переопределить его для обработки логики валидации, которую вы не можете или не хотите поместить в валидатор.

  • Метод run_validators() на поле Field запускает все валидаторы поля и объединяет все ошибки в один ValidationError. Вам не нужно переопределять этот метод.

  • Метод clean() в подклассе Field отвечает за выполнение to_python(), validate() и run_validators() в правильном порядке и распространение их ошибок. Если в любой момент времени какой-либо из методов вызывает ошибку ValidationError, валидация останавливается, и эта ошибка выдается. Этот метод возвращает чистые данные, которые затем вставляются в словарь cleaned_data формы.

  • Метод clean_<fieldname>() вызывается на подклассе формы – где <fieldname> заменяется на имя атрибута поля формы. Этот метод выполняет любую очистку, специфичную для данного атрибута, не связанную с типом поля, которым он является. Этому методу не передаются никакие параметры. Вам нужно будет найти значение поля в self.cleaned_data и помнить, что в этот момент это будет объект Python, а не исходная строка, представленная в форме (она будет в cleaned_data, потому что метод general field clean(), описанный выше, уже однажды очистил данные).

    Например, если вы хотите проверить, что содержимое CharField под названием serialnumber является уникальным, clean_serialnumber() будет подходящим местом для этого. Вам не нужно конкретное поле (это CharField), но вам нужен специфический для поля формы фрагмент проверки и, возможно, очистки/нормализации данных.

    Возвращаемое значение этого метода заменяет существующее значение в cleaned_data, поэтому это должно быть значение поля из cleaned_data (даже если этот метод не изменил его) или новое очищенное значение.

  • Метод clean() подкласса формы может выполнять валидацию, требующую доступа к нескольким полям формы. Сюда можно отнести такие проверки, как «если поле A предоставлено, то поле B должно содержать действительный адрес электронной почты». При желании этот метод может вернуть совершенно другой словарь, который будет использован в качестве cleaned_data.

    Поскольку методы валидации полей были запущены к моменту вызова clean(), у вас также есть доступ к атрибуту errors формы, который содержит все ошибки, возникшие при очистке отдельных полей.

    Обратите внимание, что любые ошибки, возникающие при переопределении Form.clean(), не будут связаны с каким-либо конкретным полем. Они попадают в специальное «поле» (называемое __all__), к которому вы можете получить доступ через метод non_field_errors(), если вам это необходимо. Если вы хотите прикрепить ошибки к определенному полю формы, вам нужно вызвать add_error().

    Также обратите внимание, что существуют особые соображения при переопределении метода clean() подкласса ModelForm. (см. ModelForm documentation для получения дополнительной информации)

Эти методы выполняются в указанном выше порядке, по одному полю за раз. То есть, для каждого поля формы (в порядке их объявления в определении формы) выполняется метод Field.clean() (или его переопределение), затем clean_<fieldname>(). Наконец, когда эти два метода выполнены для каждого поля, выполняется метод Form.clean(), или его переопределение, независимо от того, вызвали ли предыдущие методы ошибки.

Примеры каждого из этих методов приведены ниже.

Как уже упоминалось, любой из этих методов может вызвать ошибку ValidationError. Для любого поля, если метод Field.clean() вызывает ValidationError, любой метод очистки, специфичный для данного поля, не вызывается. Однако методы очистки для всех оставшихся полей все равно выполняются.

Поднятие ValidationError

Чтобы сделать сообщения об ошибках гибкими и легко переопределяемыми, примите во внимание следующие рекомендации:

  • Предоставить описательную ошибку code конструктору:

    # Good
    ValidationError(_('Invalid value'), code='invalid')
    
    # Bad
    ValidationError(_('Invalid value'))
    
  • Не вставляйте переменные в сообщение; используйте заполнители и аргумент params конструктора:

    # Good
    ValidationError(
        _('Invalid value: %(value)s'),
        params={'value': '42'},
    )
    
    # Bad
    ValidationError(_('Invalid value: %s') % value)
    
  • Используйте ключи отображения вместо позиционного форматирования. Это позволяет располагать переменные в любом порядке или вообще их не использовать при переписывании сообщения:

    # Good
    ValidationError(
        _('Invalid value: %(value)s'),
        params={'value': '42'},
    )
    
    # Bad
    ValidationError(
        _('Invalid value: %s'),
        params=('42',),
    )
    
  • Оберните сообщение символом gettext, чтобы включить перевод:

    # Good
    ValidationError(_('Invalid value'))
    
    # Bad
    ValidationError('Invalid value')
    

Собираем все вместе:

raise ValidationError(
    _('Invalid value: %(value)s'),
    code='invalid',
    params={'value': '42'},
)

Следование этим рекомендациям особенно необходимо, если вы пишете многократно используемые формы, поля форм и поля моделей.

Хотя это и не рекомендуется, если вы находитесь в конце цепочки валидации (т.е. ваша форма clean() метод) и вы знаете, что вам никогда не понадобится переопределять сообщение об ошибке, вы можете выбрать менее многословный вариант:

ValidationError(_('Invalid value: %s') % value)

Методы Form.errors.as_data() и Form.errors.as_json() значительно выигрывают от полнофункциональных ValidationErrors (с code именем и params словарем).

Возникновение множества ошибок¶

Если вы обнаружили несколько ошибок во время работы метода очистки и хотите сигнализировать обо всех из них отправителю формы, можно передать список ошибок конструктору ValidationError.

Как и выше, рекомендуется передавать список экземпляров ValidationError с codes и params, но подойдет и список строк:

# Good
raise ValidationError([
    ValidationError(_('Error 1'), code='error1'),
    ValidationError(_('Error 2'), code='error2'),
])

# Bad
raise ValidationError([
    _('Error 1'),
    _('Error 2'),
])

Использование валидации на практике¶

В предыдущих разделах объяснялось, как работает валидация в целом для форм. Поскольку иногда бывает проще понять, как работает каждая функция, здесь приведена серия небольших примеров, в которых используется каждая из предыдущих функций.

Использование валидаторов¶

Поля формы (и модели) Django поддерживают использование полезных функций и классов, известных как валидаторы. Валидатор — это вызываемый объект или функция, которая принимает значение и не возвращает ничего, если значение действительно, или выдает ошибку ValidationError, если нет. Они могут быть переданы в конструктор поля через аргумент validators или определены в самом классе Field с помощью атрибута default_validators.

Валидаторы могут использоваться для проверки значений внутри поля, давайте посмотрим на Django’s SlugField:

from django.core import validators
from django.forms import CharField

class SlugField(CharField):
    default_validators = [validators.validate_slug]

Как вы можете видеть, SlugField — это CharField с настроенным валидатором, который проверяет, что отправленный текст соответствует некоторым правилам символов. Это также можно сделать при определении поля так:

эквивалентно:

slug = forms.CharField(validators=[validators.validate_slug])

Обычные случаи, такие как проверка по электронной почте или регулярному выражению, могут быть обработаны с помощью существующих классов валидаторов, доступных в Django. Например, validators.validate_slug — это экземпляр RegexValidator, построенный с первым аргументом в виде шаблона: ^[-a-zA-Z0-9_]+$. Смотрите раздел writing validators, чтобы увидеть список того, что уже доступно, и пример того, как написать валидатор.

Очистка полей формы по умолчанию¶

Давайте сначала создадим поле пользовательской формы, которое проверяет, что его входные данные — это строка, содержащая адреса электронной почты, разделенные запятыми. Полный класс выглядит следующим образом:

from django import forms
from django.core.validators import validate_email

class MultiEmailField(forms.Field):
    def to_python(self, value):
        """Normalize data to a list of strings."""
        # Return an empty list if no input was given.
        if not value:
            return []
        return value.split(',')

    def validate(self, value):
        """Check if value consists only of valid emails."""
        # Use the parent's handling of required fields, etc.
        super().validate(value)
        for email in value:
            validate_email(email)

В каждой форме, использующей это поле, эти методы будут выполняться до того, как с данными поля можно будет сделать что-либо еще. Это очистка, специфичная для данного типа поля, независимо от того, как оно будет использоваться в дальнейшем.

Давайте создадим ContactForm, чтобы продемонстрировать, как вы будете использовать это поле:

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField()
    sender = forms.EmailField()
    recipients = MultiEmailField()
    cc_myself = forms.BooleanField(required=False)

Используйте MultiEmailField как любое другое поле формы. Когда на форме будет вызван метод is_valid(), в процессе очистки будет запущен метод MultiEmailField.clean(), который, в свою очередь, вызовет пользовательские методы to_python() и validate().

Очистка определенного атрибута поля¶

Продолжая предыдущий пример, предположим, что в нашем ContactForm мы хотим убедиться, что поле recipients всегда содержит адрес "fred@example.com". Это проверка, специфичная для нашей формы, поэтому мы не хотим помещать ее в общий класс MultiEmailField. Вместо этого мы напишем метод очистки, который работает с полем recipients, следующим образом:

from django import forms
from django.core.exceptions import ValidationError

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean_recipients(self):
        data = self.cleaned_data['recipients']
        if "fred@example.com" not in data:
            raise ValidationError("You have forgotten about Fred!")

        # Always return a value to use as the new cleaned data, even if
        # this method didn't change it.
        return data

Очистка и проверка полей, которые зависят друг от друга¶

Предположим, мы добавим еще одно требование к нашей контактной форме: если поле cc_myself является True, то subject должно содержать слово "help". Мы выполняем проверку более чем одного поля одновременно, поэтому метод формы clean() является хорошим местом для этого. Обратите внимание, что здесь мы говорим о методе clean() на форме, тогда как ранее мы писали метод clean() на поле. Важно четко различать поля и формы, когда мы решаем, где проводить валидацию. Поля — это отдельные точки данных, а формы — это набор полей.

К моменту вызова метода clean() формы будут запущены все методы очистки отдельных полей (предыдущие два раздела), поэтому self.cleaned_data будет заполнен любыми данными, которые сохранились до сих пор. Поэтому вам также нужно помнить о том, что поля, которые вы хотите проверить, могут не выдержать первоначальной проверки отдельных полей.

Есть два способа сообщить о любых ошибках на этом этапе. Вероятно, самый распространенный способ — вывести ошибку в верхней части формы. Чтобы создать такую ошибку, вы можете поднять ValidationError из метода clean(). Например:

from django import forms
from django.core.exceptions import ValidationError

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean(self):
        cleaned_data = super().clean()
        cc_myself = cleaned_data.get("cc_myself")
        subject = cleaned_data.get("subject")

        if cc_myself and subject:
            # Only do something if both fields are valid so far.
            if "help" not in subject:
                raise ValidationError(
                    "Did not send for 'help' in the subject despite "
                    "CC'ing yourself."
                )

В этом коде, если возникает ошибка валидации, форма выводит сообщение об ошибке в верхней части формы (обычно) с описанием проблемы. Такие ошибки являются не-полевыми ошибками, которые отображаются в шаблоне с помощью {{ form.non_field_errors }}.

Вызов super().clean() в коде примера гарантирует, что любая логика валидации в родительских классах будет сохранена. Если ваша форма наследует другую, которая не возвращает словарь cleaned_data в своем методе clean() (это необязательно), то не присваивайте cleaned_data результату вызова super() и используйте self.cleaned_data вместо этого:

def clean(self):
    super().clean()
    cc_myself = self.cleaned_data.get("cc_myself")
    ...

Второй подход для сообщения об ошибках валидации может включать присвоение сообщения об ошибке одному из полей. В данном случае давайте присвоим сообщение об ошибке обеим строкам «subject» и «cc_myself» в отображении формы. Будьте осторожны, делая это на практике, так как это может привести к запутанному выводу формы. Мы показываем, что здесь возможно, и предоставляем вам и вашим дизайнерам самим решать, что будет эффективно работать в вашей конкретной ситуации. Наш новый код (заменяющий предыдущий пример) выглядит следующим образом:

from django import forms

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean(self):
        cleaned_data = super().clean()
        cc_myself = cleaned_data.get("cc_myself")
        subject = cleaned_data.get("subject")

        if cc_myself and subject and "help" not in subject:
            msg = "Must put 'help' in subject when cc'ing yourself."
            self.add_error('cc_myself', msg)
            self.add_error('subject', msg)

Вторым аргументом add_error() может быть строка или, предпочтительно, экземпляр ValidationError. Более подробную информацию смотрите в Поднятие ValidationError. Обратите внимание, что add_error() автоматически удаляет поле из cleaned_data.

Пользователи часто передают в приложение некорректные данные. Такое происходит либо из злого умысла, либо по ошибке. Сто́ит проверять данные на соответствие бизнес-требованиям.

Эти бизнес-правила влияют на каждый уровень приложения. Веб-интерфейс сообщает пользователю подробные и локализованные сообщения об ошибках. Уровни бизнес-логики и хранения должны проверять приходящие от клиентов значения, перед отправкой в хранилище. База данных SQL делает окончательную проверку, чтобы гарантировать целостность хранимой информации.

Эти задачи поможет решить Bean Validation. Он интегрирован со Spring и Spring Boot. Hibernate Validator считается эталонной реализацией Bean Validation.

Идея Bean Validation в том, чтобы определять такие правила, как «Это поле не может быть null» или «Это число должно находиться в заданном диапазоне» с помощью аннотаций. Это гораздо проще, чем постоянно писать условные операторы проверок.

Hibernate Validator также задаёт правила валидации с помощью аннотаций над полями класса. Этот декларативный подход не загрязняет код. При передаче размеченного таким образом объекта класса в валидатор, происходит проверка на ограничения.

Добавьте стартер в проект, чтобы включить валидацию:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Актуальная версия Spring Boot в Maven

Спонсор поста

Используемые версии

Java 17
Spring Boot 2.7.1

История изменений статьи

26.02.2022: Обновил версию Java с 11 до 17. Также обновил версию Spring Boot до 2.6.3
29.06.2022: Spring Boot – 2.7.1. Добавил коллекцию Postman с тестами.

Валидация в контроллерах

Обычно данные сначала попадают в контроллер. У входящего HTTP запроса возможно проверить следующие параметры:

  • тело запроса.
  • переменные пути (например, id в /foos/{id}).
  • параметры запроса.

Рассмотрим каждый из них подробнее.

Валидация тела запроса

Тело запроса POST и PUT обычно содержит данные в формате JSON. Spring автоматически сопоставляет входящий JSON с объектом Java.

Разметим сущность с помощью аннотаций валидации.

public class PersonDto {

    private Long id;

    @NotBlank
    private String name;

    @Min(1)
    @Max(10)
    private int numberBetweenOneAndTen;

    @Pattern(regexp = "^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\.(?!$)|$)){4}$")
    private String ipAddress;

    // getters and setters

}

Все основные аннотации мы рассмотрим позднее, но по названиям довольно легко понять, какое условие они проверяют:

  • Поле name не должно быть пустым или null.
  • Поле numberBetweenOneAndTen должно́ находиться в диапазоне от 1 до 10, включительно.
  • Поле ipAddress должно содержать строку в формате IP-адреса.

Достаточно добавить для входящего параметра personDto аннотацию @Valid, чтобы передать объект в валидатор. Выполнение метода контролера начнётся только, если объект пройдёт все проверки.

@RestController
@RequestMapping("/api/person")
public class PersonController {

    @PostMapping
    public ResponseEntity<String> valid(@Valid @RequestBody PersonDto personDto) {
        return ResponseEntity.ok("valid");
    }

}

Вызываем наш POST метод и передаём в него не валидные данные.

Postman возвращает нам ошибку, а в консоли видим исключение. Оно сообщает нам о двух ошибках валидации.

Исключение MethodArgumentNotValidException выбрасывается, когда объект не проходит проверку. По умолчанию Spring преобразует это исключение в HTTP статус 400.

Исключение информативное, но тяжёлое для восприятия. Пользователь не получает никакой информации об ошибке. Далее мы рассмотрим, как это исправить.

Проверка переменных пути и параметров запроса

При проверке переменных пути и параметров запроса не проверяются сложные Java-объекты, так как path-переменные и параметры запроса являются примитивными типами, такими как int, или их аналогами: Integer или String.

Вместо аннотации поля класса, как описано выше, добавляют аннотацию ограничения (в данном случае @Min) непосредственно к параметру метода в контроллере:

@Validated
@RestController
@RequestMapping("/api/person")
public class PersonController {

    @GetMapping("{id}")
    public ResponseEntity<String> getById(
            @PathVariable("id") @Min(0) int personId
    ) {
        return ResponseEntity.ok("valid");
    }

    @GetMapping
    public ResponseEntity<String> getByName(
            @RequestParam("name") @NotBlank String name
    ) {
        return ResponseEntity.ok("valid");
    }

}

Обратите внимание, что необходимо добавить @Validated в контроллер на уровне класса, чтобы проверять параметры метода. В этом случае аннотация @Validated устанавливается на уровне класса, даже если она присутствует на методах.

В отличии валидации тела запроса, при неудачной проверки параметра вместо метода MethodArgumentNotValidException будет выброшен ConstraintViolationException. По умолчанию последует ответ со статусом HTTP 500 (Internal Server Error), так как Spring не регистрирует обработчик для этого исключения по умолчанию.

Валидация в сервисном слое

Можно проверять данные на любых других компонентах Spring. Для этого используется комбинация аннотаций @Validated и @Valid.

@Service
@Validated
public class PersonService {

    public void save(@Valid PersonDto personDto) {
        // do something
    }

}

Напомню, как выглядит наша сущность:

public class PersonDto {

    private Long id;

    @NotBlank
    private String name;

    @Min(1)
    @Max(10)
    private int numberBetweenOneAndTen;

    @Pattern(regexp = "^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\.(?!$)|$)){4}$")
    private String ipAddress;

    // getters and setters

}

Казалось бы, пример такой же как и в контроллере и логично ожидать MethodArgumentNotValidException, но будет выброшен ConstraintViolationException и 500 ошибка.

Проверка аргументов метода

Помимо объкетов можно проверять примитивы и их обертки, выступающие в виде аргументов метода.

Валидация сущностей JPA

Persistence Layer – это последняя линия проверки данных. По умолчанию Spring Data использует Hibernate, который поддерживает Bean Validation из коробки.

Допустим, необходимо хранить объекты нашего класса PersonDto в базе данных. Когда репозиторий пытается сохранить не валидный PersonDto, чьи аннотации ограничений нарушаются, выбрасывается ConstraintViolationException.

Bean Validation запускается Hibernate только после того как EntityManager вызовет flush().

Для отключения валидации в репозиториях установите свойство Spring Boot spring.jpa.properties.javax.persistence.validation.mode равным null.

Где проводить валидацию?

На мой взгляд, лучшее место для основной валидации это сервисный слой. У этого есть несколько причин:

  • Сервисы вызывают друг друга. Если сделать всю валидацию на контроллерах, то один сервис сможет передавать невалидные параметры в другой.
  • Валидация в репозиторном слое означает, что бизнес-код работал с потенциально невалидными объектами, что может привести к непредвиденным ошибкам. И не у всех сервисов есть этот слой.
  • Иногда ваши сервисы взаимодействиую с клиентами не только через контроллеры, что также может привести к работе с невалидными объектами в бизнесовом слое.

Конкретизация ошибок

Когда проверка не удается, лучше вернуть клиенту понятное сообщение об ошибке. Для этого необходимо вернуть структуру данных с сообщением об ошибке для каждой проверки, которая не прошла валидацию.

Я подробно описывал обработку исключений в REST API в отдельной статье. Здесь мы разберем только обработку исключений валидации.

Сначала определим структуру сообщения с ошибкой. Назовем ее ValidationErrorResponse. И этот класс содержит список объектов Violation:

@Getter
@RequiredArgsConstructor
public class ValidationErrorResponse {

    private final List<Violation> violations;

}

@Getter
@RequiredArgsConstructor
public class Violation {

    private final String fieldName;
    private final String message;

}

Затем создаем ControllerAdvice, который обрабатывает все ConstraintViolationExventions, которые пробрасываются до уровня контроллера. Чтобы отлавливать ошибки валидации и для тел запросов, мы также будем перехватывать и MethodArgumentNotValidExceptions:

@ControllerAdvice
public class ErrorHandlingControllerAdvice {

    @ResponseBody
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ValidationErrorResponse onConstraintValidationException(
            ConstraintViolationException e
    ) {
        final List<Violation> violations = e.getConstraintViolations().stream()
                .map(
                        violation -> new Violation(
                                violation.getPropertyPath().toString(),
                                violation.getMessage()
                        )
                )
                .collect(Collectors.toList());
        return new ValidationErrorResponse(violations);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ValidationErrorResponse onMethodArgumentNotValidException(
            MethodArgumentNotValidException e
    ) {
        final List<Violation> violations = e.getBindingResult().getFieldErrors().stream()
                .map(error -> new Violation(error.getField(), error.getDefaultMessage()))
                .collect(Collectors.toList());
        return new ValidationErrorResponse(violations);
    }

}

Здесь информацию о нарушениях из исключений переводится в нашу структуру данных ValidationErrorResponse.

Можно изменить сообщение об ошибке с помощью параметра message у любой аннотации валидации.

@Pattern(
        regexp = "^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\.(?!$)|$)){4}$",
        message = "Не соответствует формату IP адреса"
)
private String ipAddress;

Валидация конфигурации приложения

Spring Boot аннотация @ConfigurationProperties используется для связывания свойств из application.properties с Java объектом.

Bean Validation поможет обнаружить ошибку в этих данных при старте приложения. Допустим имеется следующий конфигурационный класс:

@Validated
@ConfigurationProperties(prefix="app.properties")
class AppProperties {

  @NotEmpty
  private String name;

  @Min(value = 7)
  @Max(value = 30)
  private Integer reportIntervalInDays;

  @Email
  private String reportEmailAddress;

  // getters and setters
}

При попытке запуска с недействительным адресом электронной почты получаем ошибку:

***
APPLICATION FAILED TO START
***

Description:

Binding to target org.springframework.boot.context.properties.bind.BindException:
  Failed to bind properties under 'app.properties' to
  io.reflectoring.validation.AppProperties failed:

    Property: app.properties.reportEmailAddress
    Value: manager.analysisapp.com
    Reason: must be a well-formed email address

Action:

Update your application's configuration

Стандартные ограничения

Библиотека javax.validation имеет множество аннотаций для валидации.

Аннотации имеют атрибуты, которые позволяют производить более тонкую настройку проверки, но каждая аннотация имеет следующие поля:

  • message – указывает на ключ свойства в ValidationMessages.properties, который используется для отправки сообщения в случае нарушения ограничения.
  • groups – позволяет определить, при каких обстоятельствах будет срабатывать эта проверка. О группах проверки поговорим позже.
  • payload – позволяет определить полезную нагрузку, которая будет передаваться сс проверкой.
  • @Constraint – указывает на реализацию интерфейса ConstraintValidator.

Рассмотрим самые популярные ограничения:

  • @NotNull — аннотированный элемент не должен быть null. Принимает любой тип.
  • @Null — аннотированный элемент должен быть null. Принимает любой тип.
  • @NotBlank — аннотированный элемент не должен быть null и должен содержать хотя бы один непробельный символ. Принимает CharSequence.
  • @NotEmpty — аннотированный элемент не должен быть null или пустым. Поддерживаемые типы:
    • CharSequence
    • Collection. Оценивается размер коллекции
    • Map. Оценивается размер мапы
    • Array. Оценивается длина массива
  • @Size — размер аннотированного элемента должен быть между указанными границами, включая сами границы. null элементы считаются валидными. Поддерживаемые типы:
    • CharSequence. Оценивается длина последовательности символов
    • Collection. Оценивается размер коллекции
    • Map. Оценивается размер мапы
    • Array. Оценивается длина массива
  • @AssertTrue проверяет, что аннотированное значение свойства истинно.
  • @Email подтверждает, что аннотированное свойство является действительным адресом электронной почты.
  • @Positive и @PositiveOrZero применяются к числовым значениям и подтверждают, что они строго положительные или положительные, включая 0.
  • @Negative и @NegativeOrZero применяются к числовым значениям и подтверждают, что они строго отрицательные или отрицательные, включая 0.
  • @Past и @PastOrPresent проверяют, что значение даты находится в прошлом или прошлом, включая настоящее.
  • @Future и @FutureOrPresent подтверждают, что значение даты находится в будущем или в будущем, включая настоящее.

Различия межу @NotNull, @NotEmpty и @NotBlank

@NotBlank применяется только к строкам и проверяет, что строка не пуста и не состоит только из пробелов.

@NotNull применяется к CharSequence, Collection, Map или Array и проверяет, что объект не равен null. Но при этом он может быть пуст.

@NotEmpty применяется к CharSequence, Collection, Map или Array и проверяет, что он не null имеет размер больше 0.

Аннотация @Size(min=6) пропустит строку состоящую из 6 пробелов и/или символов переноса строки, а @NotBlank не пропустит.

Группы валидаций

Некоторые объекты участвуют в разных вариантах использования. Возьмем типичные операции CRUD: при обновлении и создании, скорее всего, будет использоваться один и тот же класс. Тем не менее, некоторые валидации должны срабатывать при различных обстоятельствах:

  • только перед созданием
  • только перед обновлением
  • или в обоих случаях

Функция Bean Validation, которая позволяет нам внедрять такие правила проверки, называется “Validation Groups”. Все аннотации ограничений имеют поле groups. Это поле используется для передачи любых классов, каждый из которых определяет группу проверки.

Для нашего примера CRUD определим два маркерных интерфейса OnCreate и OnUpdate:

public interface Marker {

    interface OnCreate {}

    interface OnUpdate {}

}

Затем используем эти интерфейсы с любой аннотацией ограничения:

public class PersonDto {

  @Null(groups = Marker.OnCreate.class)
  @NotNull(groups = Marker.OnUpdate.class)
  private Long id;

  // ... ... ... ... ...

}

Это позволит убедиться, что id пуст при создании и заполнен при обновлении. Spring поддерживает группы проверки только с аннотацией @Validated

@Validated
@RestController
@RequestMapping("/api/group-valid/person")
public class PersonControllerGroupValid {

    @PostMapping
    @Validated({Marker.OnCreate.class})
    public ResponseEntity<String> create(@RequestBody @Valid PersonDto personDto) {
        return ResponseEntity.ok("valid");
    }

    @PutMapping
    @Validated(Marker.OnUpdate.class)
    public ResponseEntity<String> update(@RequestBody @Valid PersonDto personDto) {
        return ResponseEntity.ok("valid");
    }

}

Обратите внимание, что аннотация @Validated применяется ко всему классу. Чтобы определить, какая группа проверки активна, она также применяется на уровне метода.

Использование групп проверки может легко стать анти-паттерном.

При использовании групп валидации сущность должна знать правила валидации для всех случаев использования (групп), в которых она используется.

Создание своего ограничения

Bean Validation не ограничивается встроенными аннотациями, вы можете создавать собственные ограничения и аннотации. Пользовательские ограничения позволяют даже применять аннотации на уровне класса и проверять несколько атрибутов экземпляра класса одновременно.

Напишем свою аннотацию, которая будет проверять, что строка начинается с большой буквы. Сначала создаем аннотацию @CapitalLetter:

@Target({ FIELD })
@Retention(RUNTIME)
@Constraint(validatedBy = CapitalLetterValidator.class)
@Documented
public @interface CapitalLetter {

  String message() default "{CapitalLetter.invalid}";

  Class<?>[] groups() default { };

  Class<? extends Payload>[] payload() default { };

}

Реализация валидатора выглядит следующим образом:

public class CapitalLetterValidator implements ConstraintValidator<CapitalLetter, String> {

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value != null && !value.isEmpty()) {
            return Character.isUpperCase(value.charAt(0));
        }
        return true;
    }

}

Теперь можно использовать аннотацию @CapitalLetter, как и любую другую аннотацию ограничения.

public class PersonDto {

  // ... ... ... ... ...

  @NotBlank
  @CapitalLetter
  private String name;

  // ... ... ... ... ...

}

Принудительный вызов валидации

Для принудительного вызова проверки, без использования Spring Boot, создайте валидатор вручную.

public class ProgrammaticallyValidatingService {

  public void validateInput(PersonDto personDto) {
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validator = factory.getValidator();
    Set<ConstraintViolation<personDto>> violations = validator.validate(personDto);
    if (!violations.isEmpty()) {
      throw new ConstraintViolationException(violations);
    }
  }

}

Тем не менее, Spring Boot предоставляет предварительно сконфигурированный экземпляр валидатора. Внедрив этот экземпляр в сервис не придется создавать его вручную.

@Service
public class ProgrammaticallyValidatingService {

  private Validator validator;

  public ProgrammaticallyValidatingService(Validator validator) {
    this.validator = validator;
  }

  public void validateInputWithInjectedValidator(PersonDto personDto) {
    Set<ConstraintViolation<PersonDto>> violations = validator.validate(personDto);
    if (!violations.isEmpty()) {
      throw new ConstraintViolationException(violations);
    }
  }

}

Резюмирую

Валидация это неотъемлимая часть бизнес логики. Используя зависимость spring-boot-starter-validation, мы можем облегчить себе работу.

Валидацию делают при переходе данных из одного архитектурного слоя в другой, чтобы не разрушить логику принимаемого слоя. Также можно настроить валидацию конфигурации приложения.

Стоит возвращать клиенту понятное описание ошибки валидации, используя @ControllerAdvice.

Понравилась статья? Поделить с друзьями:
  • Validation error text
  • Validation error template wpf
  • Validation error response
  • Validation error python
  • Validation error please try again if this error persists please contact the site administrator