Пользовательские сообщения об ошибках в сериализаторе Django Rest Framework

Сценарий довольно прямолинейный:

У меня есть модель с некоторыми полями, которые требуются. Скажем, один из них - TextField, который не может быть blank. У меня также есть ModelSerializer (Django Rest Framework), который представляет эту модель.

Когда пустая строка используется для установки этого поля через сериализатор, возвращаемая ошибка исходит от самой модели (This field can't be blank).

Я хотел бы переопределить сообщения об ошибках только на уровне сериализатора без необходимости явно переопределять каждое поле в сериализаторе (что, по моему мнению, противоречит принципу DRY), нужно написать метод validate_ для каждое поле и поднять мой собственный ValidationError или изменить сообщения об ошибках на уровне Model (потому что иногда контекст сообщения об ошибке имеет значение для моего прецедента, и сообщение об ошибке должно быть указано соответственно).

Другими словами, существует ли способ переопределить сообщения об ошибках на уровне сериализатора так же просто, как и для ModelForm:

class MyModelForm(ModelForm):
    class Meta:
        model = MyModel
        error_messages = {"field1": {"required": _("For some reason this is a custom error message overriding the model default")}}

Ответ 1

EDIT: Я вижу, что этот вопрос по-прежнему получает некоторые взгляды, поэтому важно отметить, что существует другой подход, намного более чистый, чем исходный ответ, который я разместил здесь.

Вы можете использовать атрибут extra_kwargs для класса Meta-сериализатора, например:

class UserSerializer(ModelSerializer):

    class Meta:
        model = User
        extra_kwargs = {"username": {"error_messages": {"required": "Give yourself a username"}}}

Оригинальный ответ:

Используя ответ @mariodev, я создал новый класс в моем проекте, который делает это:

from rest_framework.serializers import ModelSerializer, ModelSerializerOptions

class CustomErrorMessagesModelSerializerOptions(ModelSerializerOptions):
    """
    Meta class options for CustomErrorMessagesModelSerializerOptions
    """
    def __init__(self, meta):
        super(CustomErrorMessagesModelSerializerOptions, self).__init__(meta)
        self.error_messages = getattr(meta, 'error_messages', {})

class CustomErrorMessagesModelSerializer(ModelSerializer):
    _options_class = CustomErrorMessagesModelSerializerOptions

    def __init__(self, *args, **kwargs):
        super(CustomErrorMessagesModelSerializer, self).__init__(*args, **kwargs)

        # Run through all error messages provided in the Meta class and update
        for field_name, err_dict in self.opts.error_messages.iteritems():
            self.fields[field_name].error_messages.update(err_dict)

Первый дает возможность добавить новый атрибут класса Meta к сериализатору, как и к ModelForm. Второй наследует от ModelSerializer и использует метод @mariodev для обновления сообщений об ошибках.

Все осталось сделать, просто наследовать его и сделать что-то вроде этого:

class UserSerializer(CustomErrorMessagesModelSerializer):
    class Meta:
        model = User
        error_messages = {"username": {"required": "Give yourself a username"}}

Ответ 2

В вашем сериализаторе:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User

    def __init__(self, *args, **kwargs):
        super(UserSerializer, self).__init__(*args, **kwargs)

        self.fields['username'].error_messages['required'] = u'My custom required msg'

Обратите внимание, что некоторые сообщения об ошибках состоят из %s заполнителей, таких как:

'invalid': _("'%s' value must be either True or False."),

для BooleanField.

Поэтому вам нужно пройти часть default_error_messages в каждом типе поля в DRF fields.py, чтобы использовать его правильно.

Ответ 3

unique, казалось, игнорировался из error_messages, поэтому мне пришлось придерживаться другого подхода.

email = serializers.EmailField(validators=[
    UniqueValidator(
        queryset=models.Client.objects.all(),
        message="My custom error",
    )]
)

Это более простой (но менее гибкий, менее многоразовый), чем @gabriel-amram, но гораздо менее хакерский, чем @mariodev's.

Ответ 4

Другой подход для UniqueValidator (для использования с ModelSerializer):

def __init__(self, *args, **kwargs):
    super(UserSerializer, self).__init__(*args, **kwargs)
    # Find UniqueValidator and set custom message
    for validator in self.fields['email'].validators:
        if isinstance(validator, validators.UniqueValidator):
            validator.message = _('This email already exist on this site')

Ответ 5

Просто примечание, так как я некоторое время играл с этим, если вы используете что-то вроде URLField, который просто добавляет URLValidator, он, похоже, не использует error_messages, поэтому я сделал что-то похожее на @Hugo answer

class Meta:
    extra_kwargs = {"url_field": {"validators": [validators.URLValidator(message="My error message")]}}

Ответ 6

DRF3.0 ожидает, что мы будем явно определять валидаторы для полей, если мы хотим переопределить модели валидаторов по умолчанию. Это можно сделать, передав extra_kwargs и явно определяя валидаторы для любого поля вам кажется необходимым. Также вы можете указать свой собственный валидатор, который может быть повторно использован для разных полей или даже других сериализаторов

http://www.django-rest-framework.org/api-guide/serializers/#validation

http://www.django-rest-framework.org/api-guide/validators/#validation-in-rest-framework

# my_app/validators.py
def validate_required(value):
    # whatever validation logic you need
    if value == '' or value is None:
        raise serializers.ValidationError('This field is required.')

# my_app/serializers.py
class MyModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = MyModel
        extra_kwargs = {"field1": {"validators": [validators.validate_required,]}}