Search code examples
djangodjango-modelsdjango-rest-frameworkdjango-validationdjango-serializer

Customizing ModelSerializer error message is being ignored


This is my UserSerializer (I'm using the default Django User model):

class UserSerializer(SetCustomErrorMessagesMixin, serializers.ModelSerializer):

    def __init__(self, *args, **kwargs):
            super(UserSerializer, self).__init__(*args, **kwargs) # call the super() 
            for field in self.fields: # iterate over the serializer fields
                self.fields[field].error_messages['required'] = 'Enter a valid %s.'%field
                self.fields[field].error_messages['null'] = 'Enter a valid %s.'%field

                # class CharField(Field) errors
                self.fields[field].error_messages['blank'] = 'Enter a valid %s.'%field
                self.fields[field].error_messages['max_length'] = '%s cannot have more than {max_length} characters.'%field
                self.fields[field].error_messages['min_length'] = '%s cannot have less than {min_length} characters.'%field

    class Meta:
        model = User
        fields = ('username', 'password', 'email',)

The problem is, when a user inputs a username which is too long, the error message is

"Username is too long."

Where is this error message coming from? I overwrote the "max_length" error message in the code above, but it does not show it. When I delete this line from my UserSerialzer:

self.fields[field].error_messages['max_length'] = '%s cannot have more than {max_length} characters.'%field

then the error message is:

"Ensure this field has no more than 30 characters."

which makes sense beause it is coming from the CharField DRF source code here: https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/fields.py

But where is "Username is too long." coming from and how come it does not say "Username cannot have more than {max_length} characters." instead?


Solution

  • The problem appears to be that DRF adds validators for fields during their construction and copies the error messages from field classes.

    For example from rest_framework.fields.CharField.__init__:

    if self.min_length is not None:
        message = self.error_messages['min_length'].format(min_length=self.min_length)
        self.validators.append(MinLengthValidator(self.min_length, message=message))
    

    So at the moment you are overwriting the messages, they are already used in the validators.

    I think you can just create a yourapp.fields module where you subclass DRF serializer fields and override their default_error_messages, like so:

    from rest_framework import fields
    
    class CharField(fields.CharField):
    
        default_error_messages = {
            # Your messages
        }
    

    And then just switch the module you import fields from.

    You might also want to override __init__s to add field names in messages.