validate - update django serializer




Mensagens de erro personalizadas no serializador do Django Rest Framework (5)

Apenas uma observação desde que eu brinquei com isso por algum tempo, se você estiver usando algo como um URLField que apenas adiciona um URLValidator, ele não parece usar as mensagens de erro, então fiz algo semelhante à resposta de @ Hugo:

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

O cenário é bastante direto:

Eu tenho um modelo com alguns campos que são obrigatórios. Digamos que um deles seja um TextField que não possa ficar em blank . Eu também tenho um ModelSerializer (Django Rest Framework) que representa esse modelo.

Quando uma string vazia é usada para definir esse campo através do serializador, o erro retornado vem do próprio modelo ( This field can't be blank ).

Gostaria de substituir as mensagens de erro apenas no nível do serializador, sem a necessidade de especificar novamente explicitamente todos os campos no serializador (o que acredito ser contrário ao princípio DRY), tendo que escrever um método validate_ para cada campo e aumentar minha próprio ValidationError ou ter que alterar as mensagens de erro no nível do Model (porque às vezes o contexto da mensagem de erro é importante para o meu caso de uso e a mensagem de erro deve ser fornecida de acordo).

Em outras palavras, existe uma maneira de substituir mensagens de erro no nível do serializador tão fácil quanto para um ModelForm :

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

Eu tentei criar um Serializer simples em vez de um ModelSerializer . Provavelmente por isso, a resposta aceita com extra_kwargs de Gabriel Amram não funcionou para mim. Outra resposta importante de @mariodev funcionou, mas eu estava procurando uma solução mais elegante e encontrei uma. Acontece que a classe Field aceita mensagens de erro como parâmetro, que é um dicionário que substitui as mensagens de erro padrão. Aqui está a referência aos documentos . É o mesmo formato descrito nas respostas aceitas. Aqui está um exemplo:

from rest_framework import serializers

class MySerializer(serializers.Serializer):
    client_id = serializers.IntegerField(required=True, error_messages={'required': 'Custom error message'})

O DRF3.0 espera que definamos explicitamente os validadores para os campos, se desejarmos substituir os validadores de modelo padrão. Isso pode ser feito passando extra_kwargs e definindo explicitamente os validadores para o campo que você parecer necessário. Também é possível especificar seu próprio validador personalizado, que pode ser reutilizado novamente para campos diferentes ou até outros serializadores

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,]}}

Outra abordagem para UniqueValidator (para usar com 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')

EDIT: Vejo que essa pergunta ainda recebe algumas visualizações, por isso é importante observar que há outra abordagem, muito mais limpa do que a resposta original que publiquei aqui.

Você pode apenas usar o atributo extra_kwargs da classe Meta do serializador, assim:

class UserSerializer(ModelSerializer):

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

Resposta original:

Usando a resposta do @mariodev, criei uma nova classe no meu projeto que faz isso:

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)

O primeiro oferece a possibilidade de adicionar um novo atributo de classe Meta ao serializador, como no ModelForm . O segundo herda do ModelSerializer e usa a técnica do @ mariodev para atualizar as mensagens de erro.

Tudo o que resta, é apenas herdá-lo e fazer algo assim:

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