cheslijones
cheslijones

Reputation: 9194

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

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?

Upvotes: 5

Views: 3720

Answers (1)

Mahmoud Adel
Mahmoud Adel

Reputation: 1330

You are using a ModelSerializer with your model and the 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 creation validators will be applied and as the 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

Upvotes: 10

Related Questions