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.