[Django]-Get value of another field in Field level Validation in DRF

35πŸ‘

βœ…

No that is not possible. If you need to access more than one value you have to use the Object-level validation (see docs):

class Keys_Serializer(serializers.Serializer):

    key_id = serializers.IntegerField(required=True)
    key_name = serializers.CharField(required=True)
    value_id = serializers.IntegerField(required=False)

    def validate(self, data):
        # here you can access all values
        key_id = data['key_id']
        value_id = data['value_id']
        # perform you validation
        if key_id != value_id:
            raise serializers.ValidationError("key_id must be equal to value_id")
        return data

12πŸ‘

I dug around codebase of drf a little bit. You can get values of all fields using following approach. This way you can throw serialization error as {'my_field':'error message} instead of {'non_field_error':'error message'}

def validate_myfield(self, value):
   data = self.get_initial() # data for all the fields
   #do your validation

However, if you wish to do it for ListSerializer, i.e for serializer = serializer_class(many=True), this won’t work. You will get list of empty values. In that scenario, you could write your validations in def validate function and to avoid non_field_errors in your serialization error, you can raise ValidationError with error message as a dictionary instead of string.

def validate(self, data):
    # do your validation
    raise serializers.ValidationError({"your_field": "error_message"})

1πŸ‘

def validate(self, validated_data):
        """
        validate and verifies the user data before getting saved.
        :param validated_data: dict obj
        :return: validated_data
        """

        existing_data = self.to_representation(self.instance)

0πŸ‘

So if you’re performing a create or update the plain unvalidated data can accessed in:

self.context['view'].get_serializer().data

Although the other solutions are in fact cleaner, we have a single model on a partitioned table and need another field that specifies the partition, since we’re not partitioned on the primary key the database has no clue how to look it up.

EDIT: It appears that field is actually blank, you may have luck with the following, depending on how the Serializer is used (for this it must be used in a ViewSet)

self.context['view'].get_serializer().context['request'].data

0πŸ‘

One other simple solution is accessing the properties as below

class Keys_Serializer(serializers.Serializer):

key_id = serializers.IntegerField(required=True)
key_name = serializers.CharField(required=True)
value_id = serializers.IntegerField(required=False)

def validate_key_name(self, value):
    #getting other field values as below
    self.initialdata
    #scrape data from initialdata
    # incase of updation time use 
    # self.instance and self.inistialdata together to get respective ones
    return  value

    

0πŸ‘

I had a similar problem where I just needed other values for the output, not for validation but this could probably be a good starting point. It is based on https://www.django-rest-framework.org/api-guide/fields/#examples.

You need to override the get_attribute function to return the object instead of the attribute. From the docs:

class ClassNameField(serializers.Field):
def get_attribute(self, instance):
    # We pass the object instance onto `to_representation`,
    # not just the field attribute.
    return instance

Then I was able to do stuff like

def to_representation(self, instance):  # pylint: disable=arguments-renamed
    return instance.my_function()
    or 
    return f"{instance.attribute_1}, {instance.attribute_2}"

-1πŸ‘

def validate_fieldname(self, value):
   data = self.context['request'].data

Leave a comment