"user with this username already exists" in DRF ModelSerializer if not specified explicitly

Viewed 2101

I'm trying understand why this error occurs even though I know how to resolve. Just trying to understand DRF and Django better.

JSON in this format comes from the FE:

{
  "username": "username_here",
  "password": "password_here"
}

I have this view:

class UserSigninTokenAPIView(APIView):
    permission_classes = [AllowAny]
    serializer_class = UserSigninTokenSerializer

    def post(self, request):
        data = request.data
        serializer = UserSigninTokenSerializer(data=data)
        if serializer.is_valid(raise_exception=True):
            new_data = serializer.data
            return Response(new_data, status=HTTP_200_OK)
        return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)

Which uses this serializers:

class UserSigninTokenSerializer(ModelSerializer):
    username = CharField()

    class Meta:
        model = USERS
        fields = [
            'username',
            'password',
            'id'
        ]

    def validate(self, data):
        username = data['username']
        password = data['password']
        user_qs = USERS.objects.filter(username__iexact=username)
        if user_qs.exists() and user_qs.count() == 1:
            user_obj = user_qs.first()
            password_passes = user_obj.check_password(password)
            if password_passes:
                """
                A number of checks here I removed to keep this clean,
                otherwise would just use /api/token/ to get a token.
                I want user checks to pass before issuing a token,
                because having the token is what indicates they are 
                logged in successfully.
                """
                token = RefreshToken.for_user(user_obj)
                return {
                    'refresh': str(token),
                    'access': str(token.access_token)
                }
            else:
                Services.user_attempts(user_obj)
        raise ValidationError({'error': '''
            The credentials provided are invalid.
            <br>Please verify the username and password are correct.
        '''})

The username = CharField() seems redundant to me. The documentation says:

The ModelSerializer class provides a shortcut that lets you automatically create a Serializer class with fields that correspond to the Model fields.

I interpret this as saying just specifying the field = [] in the class Meta: is sufficient for deserializing the JSON.

However, when I remove the username = CharField(), I get a:

{
    "username": [
        "user with this username already exists."
    ]
}

The documentation for explicit specifications says:

You can add extra fields to a ModelSerializer or override the default fields by declaring fields on the class, just as you would for a Serializer class.

This makes it sound optional, but apparently it is mandatory to specify it.

What am I missing here if someone wouldn't mind explaining?

1 Answers

You are using a ModelSerializer with your model and request is POST, there is no wonder why you are getting this.

ModelSerializer is used to provide a quick standard serialization for CRUD operations, so when your request is POST your serializer will assume that you are creating a new user with the request data for Users model, so creating validations will be applied and as username is unique..., you now the rest of the story.

Try to use a basic Serializer as you only want to read data it will be simpler

Related