2

I'm having trouble getting data in validate() function of Serializer for my API. I'm using django AbstractUser Model

Django = "^3.1.3"
djangorestframework = "^3.12.2"

My serializers.py:

class ChangePasswordSerializer(serializers.Serializer):
    old_password = serializers.CharField(max_length=255, required=True)
    new_password = serializers.CharField(max_length=255, required=True, write_only=True)
    new_password_confirm = serializers.CharField(max_length=255, required=True, write_only=True)

    def validate_old_password(self, value):
        if not self.context['user'].check_password(value): # got data
            raise serializers.ValidationError("Incorrect Old Password") 
    
    def validate_new_password(self, value):
        try:
             # validate the password and catch the exception
            validators.validate_password(password=value) # got data

         # the exception raised here is different than serializers.ValidationError
        except exceptions.ValidationError as e:
            raise serializers.ValidationError(list(e)) 
    
    def validate_new_password_confirm(self, value):
        try:
             # validate the password and catch the exception
            validators.validate_password(password=value) # got data

         # the exception raised here is different than serializers.ValidationError
        except exceptions.ValidationError as e:
            raise serializers.ValidationError(list(e)) 
    
    def validate(self, data):
        if data['new_password'] != data['new_password_confirm']: # both return None
            raise serializers.ValidationError({'message': ["Your password and confirmation password do not match."]})
        
        return data

views.py:

class change_password(APIView):

    def post(self, request):
        received_json_data=request.data
        user = request.user
        serializer = ChangePasswordSerializer(data=received_json_data, context={'user': user})
        if serializer.is_valid():
            user.set_password(received_json_data['new_password']) # got new_password
            return JsonResponse({
                'message': 'Password changed.'
            }, status=200)
        else:
            return JsonResponse({'message':serializer.errors}, status=400)

The problem is in validate(self, data) the data currently return as OrderedDict([('old_password', None), ('new_password', None), ('new_password_confirm', None)]) so it skipped the custom validation, but in other validation methods validate_old_password , validate_new_password and validate_new_password_confirm i got value normally when i print it out

I'm so confused on why this is happening

1 Answer 1

4

You always have to return the value in the validation methods.

Instead of this which doesn't return the value:

def validate_old_password(self, value):
    if not self.context['user'].check_password(value): # got data
        raise serializers.ValidationError("Incorrect Old Password") 

you have to write this:

def validate_old_password(self, value):
    if not self.context['user'].check_password(value): # got data
        raise serializers.ValidationError("Incorrect Old Password")

    return value 

This is also the reason why the validate method doesn't receive the data since the validation methods for the individual fields run first.

Sign up to request clarification or add additional context in comments.

2 Comments

oh i see, it's weird the first 3 validations doesn't notify error need to return like the one in validate() if missing return data. Also the docs not mentioning much ;-; django-rest-framework.org/api-guide/validators/#optional-fields. But thank you for answering, it worked ( i will accept when it allowed me to)
The field-level validation chapter is mentioned here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.