Поле JSON иногда содержит строку, иногда объект
Я использую Django rest framework для валидации JSON, полученного от API, который принимает финансовые транзакции. Сериализатор работает уже несколько лет. Поле merchant в JSON всегда содержало продавца в виде вложенного объекта с ID продавца, именем и т.д. Но теперь я иногда получаю только ID продавца в виде строки, и JSON теперь не проходит валидацию.
Как настроить сериализатор, чтобы в поле merchant можно было указать либо строку, либо объект?
В основном поля торговца должны принимать одно из этих полей:
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)
Для поля required необходимо установить значение false.name
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)
Надеюсь, это может помочь.
Вы можете переопределить to_internal_value таким образом, чтобы он пытался разобрать переданные данные. В приведенном ниже решении он просто проверяет, являются ли данные словарем, и устанавливает их в словарь, если это не так.
Это решение позволит сериализатору принимать строку, но внутри сериализатора она станет словарем, содержащим только ключ id.
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)
Вероятно, вам придется изменить некоторые валидации в сериализаторе, чтобы он мог принимать только id, хотя.