Ali Kazemkhanloo
Ali Kazemkhanloo

Reputation: 1159

make a write_only field conditionally required in django rest framework

I have a field in my serializer which is required conditional on value of another field. say password is required only if registerField is email.

I have this serializer

class UserSerializer(ModelSerializer):
    ...
    password = CharField(write_only=True, required=False)

    def validate(self, data):
        if 'email' in data.keys() and 'password' not in data.keys():
            raise ValidationError({'password', 'this field is required'})
        return data

this method works, but the response is:

{
    "non_field_errors": [
        "{'this filed is required', 'password'}"
    ]
}

When I remove write_only I get

{
    "password":["this filed is required"]
}

which is what I want to get with write_only

versions:

djangorestframework==3.8.2
django==2.2.12

Upvotes: 1

Views: 946

Answers (2)

Luiz Mateus
Luiz Mateus

Reputation: 21

I solved it in the init:

class AdministratorSerializer(serializers.ModelSerializer):
#...other fileds
password = serializers.CharField(source='user.password', write_only=True)
class Meta:
    model = Administrator
    fields = ['password']
    extra_kwargs = {'password': {'write_only': True}}

def __init__(self, *args, **kwargs):
    super(AdministratorSerializer, self).__init__(*args, **kwargs)
    request = self.context.get('request')
    if request and request.method == 'POST':
        self.fields['password'].required = True
    else:
        self.fields['password'].required = False

Upvotes: 0

Akash Pagar
Akash Pagar

Reputation: 637

Simply use raise serializers.ValidationError({'password': "this field is required"}) instead of raise ValidationError({'password': "this field is required"}) in validate method. Check Object-Level-Validations

from rest_framework import serializers
  ...
 
     def validate(self, attrs):
        if 'email' in attrs.keys() and 'password' not in attrs.keys():
            raise serializers.ValidationError({'password': "this field is required"})
        return attrs

Above is just a quick solution in your case, but DRF provides single field-level validation methods too.

Note: for using this ValidationError as per DRF:

The recommended style for using ValidationError is to keep it namespaced under serializers, in order to minimize potential confusion with Django's built-in ValidationError. For example:

from rest_framework import serializers
raise serializers.ValidationError('Value was invalid')

Field-level-validations

You can write def validate_password(self, data): method too, in which you can raise ValidationError("field is required") with all validations regarding a particular field if (required=True) in serializer field.

In field-level validation request data can be retrieved from using this statement.

request_data = self.context['view'].request.data

Upvotes: 2

Related Questions