django rest framework: установить ошибку на уровне поля из метода serialify validate()

У меня есть сериализатор, который проверяет поля на основе значений других полей. В ответе об ошибке я хотел бы показать каждую ошибку поля как полевую ошибку, а не показывать все под "non_field_errors", что и произойдет, если я буду поднимать ValidationError в методе проверки уровня объекта. Ниже приведен пример того, чего я пытаюсь достичь:

MySerializer(ModelSerializer):
    ...
    def validate(self, data):
        field_val1 = data['field_val1']
        field_val2 = data['field_val2']
        if not self._is_field_valid(field_val1, field_val2):
            # The below line is how I would do what I want with Django
            # Forms, however, it not valid in DRF
            self._errors['field_val1'] = 'this field is not valid'

Требуемый ответ об ошибке:

{'field_val1': ['this field is not valid']}

Ответ 1

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

Если я raise ValidationError({'field_val1': ['this field is not valid']}) Я получаю ответ JSON, который я хочу.

Ответ 2

Подобно ответу @Jkk.jonah, это вызывает ValidationError, но он повторно использует исходный текст исключения без необходимости повторной реализации переводов:

try:
    serializer.fields['field_val1'].fail('required')
except ValidationError as exc:
    raise ValidationError({
        'field_val1': exc.detail,
    })

По умолчанию (т.е. по классу rest_framework.fields.Field) доступными ключами являются:

default_error_messages = {
    'required': _('This field is required.'),
    'null': _('This field may not be null.')
}

Подклассы могут добавлять там свои собственные сообщения об ошибках (и Serializer - подкласс Field).

BTW, новые сообщения об ошибках будут автоматически объединены с существующими (унаследованными) сообщениями - не будут переопределены, как можно было бы ожидать.

Ответ 3

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

def validate(self, data):
    for key, value in data.items():
        # checks if value is empty
        if not value:
            raise serializers.ValidationError({key: "This field should not be left empty."})

    return data