DjangoRestFramework serializer does not recognize 'username' attribute even though it exists

1.2k views Asked by At

This is my serializers.py:

from rest_framework import serializers
from django.contrib.auth.models import User
from CMSApp.mixins import SetCustomErrorMessagesMixin

from django.utils.translation import gettext as _
from rest_framework.validators import UniqueValidator
from django.core.validators import RegexValidator


class UserSerializer(SetCustomErrorMessagesMixin, serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ('username', 'password', 'email')
        custom_error_messages_for_validators = {
            'username': {
                UniqueValidator: _('This username is already taken. Please, try again'),
                RegexValidator: _('Invalid username')
            }
        }

    def create(self, validated_data):
        user = User.objects.create_user(
            email = validated_data['email'],
            username = validated_data['username'],
            password = validated_data['password'],
        )
        return user

and this is my mixins.py:

class SetCustomErrorMessagesMixin:
    """
    Replaces built-in validator messages with messages, defined in Meta class. 
    This mixin should be inherited before the actual Serializer class in order to call __init__ method.

    Example of Meta class:

    >>> class Meta:
    >>>     model = User
    >>>     fields = ('url', 'username', 'email', 'groups')
    >>>     custom_error_messages_for_validators = {
    >>>         'username': {
    >>>             UniqueValidator: _('This username is already taken. Please, try again'),
    >>>             RegexValidator: _('Invalid username')
    >>>         }
    >>>     }
    """
    def __init__(self, *args, **kwargs):
        # noinspection PyArgumentList
        super(SetCustomErrorMessagesMixin, self).__init__(*args, **kwargs)
        self.replace_validators_messages()

    def replace_validators_messages(self):
        for field_name, validators_lookup in self.custom_error_messages_for_validators.items():
            # noinspection PyUnresolvedReferences
            for validator in self.fields[field_name].validators:
                if type(validator) in validators_lookup:
                    validator.message = validators_lookup[type(validator)]

    @property
    def custom_error_messages_for_validators(self):
        meta = getattr(self, 'Meta', None)
        return getattr(meta, 'custom_error_messages_for_validators', {})

When I go to the URL /users/1, this is the view which is called:

class user_detail(APIView):
    """
    Get, update or delete a specific user.
    """
    def get_object(self, pk):
        try:
            return User.objects.get(pk=pk)
        except User.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

    def get(self, request, pk):
        user = self.get_object(pk)
        serializer = UserSerializer(user)
        return Response(serializer.data)

    def put(self, request, pk):
        user = self.get_object(pk)
        serializer = UserSerializer(user, data=request.DATA)
        if serialzier.is_valid():
            serializier.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk):
        user = self.get_object(pk)
        user.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

The issue is, when I go to the URL /users/1, Django returns an attribute error, saying:

AttributeError at /CMS/users/1
Got AttributeError when attempting to get a value for field `username` on serializer `UserSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Response` instance.
Original exception text was: 'Response' object has no attribute 'username'.

I checked my UserSerializer and I did specify correctly that

fields = ('username', 'password', 'email')

so I can't seem to find the issue. Any idea why Django is giving an error saying that "The serializer field might be named incorrectly and not match any attribute or key on the Response instance." even though 'username' is named correctly?

1

There are 1 answers

2
Kevin Brown-Silva On BEST ANSWER

The issue is in your get_object method, you're returning a 404 response instead of raising a Http404 exception. Because of that, the Response is being passed into your serializer, and clearly the Response does not have a username field.

The last part of your stack trace said

Original exception text was: 'Response' object has no attribute 'username'.

Which was the signal: there is only one place where you are returning a Response back to a serializer.