Home > Mobile >  JSON field sometimes contains string, sometimes object
JSON field sometimes contains string, sometimes object

Time:05-18

I'm using Django rest framework to validate JSON received from an API that receives financial transactions. The serializer has been working for a few years now. The merchant field in the JSON would always contained the merchant as a nested object with the merchant's ID, name etc. But now I am sometimes receiving just the merchant's ID as a string and the JSON now fails validation.

How do I set up my serializer to allow eith string or object in the merchant field?

Basically the merchant fields needs to accept either of these:

merchant = MerchantSerializer(required=False, allow_null=True)
merchant = serializers.CharField(required=False, max_length=50)

serializers.py

class MerchantSerializer(serializers.Serializer):
    id = serializers.CharField(required=True, max_length=50)
    name = serializers.CharField(required=True, max_length=100)
    atm = serializers.BooleanField(required=False, allow_null=True)
    address = AddressSerializer(required=False, allow_null=True)
    logo = serializers.URLField(required=False, allow_null=True, max_length=500, min_length=None, allow_blank=True)

class DataSerializer(serializers.Serializer):
    account_id = serializers.CharField(required=True, max_length=50)
    amount = serializers.IntegerField(required=True)
    created = serializers.DateTimeField()
    currency = serializers.CharField(required=True, max_length=3)
    description = serializers.CharField(required=True, max_length=250)
    id = serializers.CharField(required=True, max_length=50)
    category = serializers.CharField(required=True, max_length=100)
    decline_reason = serializers.CharField(required=False, allow_null=True, allow_blank=True, max_length=100)
    merchant = MerchantSerializer(required=False, allow_null=True)
    counterparty = CounterpartySerializer(required=False, allow_null=True)
    metadata = MetadataSerializer(required=False, allow_null=True)

CodePudding user response:

You can override to_internal_value such that, it would try to parse the passed data. In the solution below, it's just checking if the data is a dictionary and set it to a dictionary if it's not.

This solution will allow the serializer to accept a string but within the serializer it will become a dictionary containing a key id only.

class MerchantSerializer(serializers.Serializer):
    id = serializers.CharField(required=True, max_length=50)
    # other fields ...

    def to_internal_value(self, data):
        parsed_data = data
        if not isinstnace(parsed_data, dict):
            parsed_data = { "id": data }
        return super().to_internal_value(parsed_data)

You will probably have to change some validations on the serializer to allow it to receive only id though.

CodePudding user response:

You need to set required to false for the name field.

class MerchantSerializer(serializers.Serializer):
    id = serializers.CharField(required=True, max_length=50)
    name = serializers.CharField(required=False, max_length=100)   # this field
    atm = serializers.BooleanField(required=False, allow_null=True)
    address = AddressSerializer(required=False, allow_null=True)
    logo = serializers.URLField(required=False, allow_null=True, max_length=500, min_length=None, allow_blank=True)

Hope it could help.

  • Related