Передача вложенных данных в Django ModelSerializer

Я хочу узнать, как можно передать вложенные данные в ModelSerializer, если дочерняя часть вложенных данных не является самостоятельной моделью.

Данные, с которыми я работаю, выглядят следующим образом:

{
  'leadId': 12345,
  'updateTime': 1651250096821,
  'changeInfo': {
    'oldstage': 'New Leads',
    'newstage': 'Attempting Contact'
  }
}

Из предыдущего опыта я знаю, что если бы я работал только с leadId и updateTime, мой сериализатор выглядел бы следующим образом:

class LogSerializer(serializers.ModelSerializer):
    leadId = serializers.IntegerField(source="lead_id")
    updateTime = serializers.IntegerField(source="update_time")

    class Meta:
        model = Log
        fields = ["leadId", "updateTime"]

Что позволит сделать следующее:

data = {
    'leadId': 12345,
    'updateTime': 1651250096821
}
serializer = LogSerializer(data=data)
serializer.is_valid()
serializer.save()

Если я не хочу превращать changeInfo в собственную модель, возможно ли отобразить поля на вложенные данные? Что-то, что могло бы выглядеть так (но это, очевидно, не работает):

class LogSerializer(serializers.ModelSerializer):
    leadId = serializers.IntegerField(source="lead_id")
    updateTime = serializers.IntegerField(source="update_time")
    oldstage = serializers.IntegerField(source="oldstage")
    newstage = serializers.IntegerField(source="newstage")


    class Meta:
        model = Log
        fields = ["leadId", "updateTime", "oldstage", "newstage]

Вы можете использовать пользовательский сериализатор для вашего поля changeInfo (для этого не нужно создавать модель):

class ChangeInfoSerializer(serializers.Serializer):
    oldstage = serializers.CharField(max_length=100) # Set max_length to a value that suits your needs
    newstage = serializers.CharField(max_length=100)

    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass


class LogSerializer(serializers.ModelSerializer):
    leadId = serializers.IntegerField(source="lead_id")
    updateTime = serializers.IntegerField(source="update_time")
    changeInfo = ChangeInfoSerializer(required=False) # Change to required=True if you want this field to be mandatory
    

    class Meta:
        model = Log
        fields = ["leadId", "updateTime", "changeInfo"]

    def create(self, validated_data):
        change_info = validated_data.pop('changeInfo')
        log = Log.objects.create(**validated_data)
        
        # Here you can use change_info['oldstage'] and change_info['newstage'] if 'changeInfo' is sent (otherwise you'll get a KeyError)
        # You should add your custom logic here, dont forget to call log.save() if you make any updates to the log created
        
        return log

    def update(self, instance, validated_data):
        change_info = validated_data.pop('changeInfo')
        
        instance.lead_id = validated_data.get('leadId', instance.lead_id)
        instance.update_time = validated_data.get('updateTime', instance.update_time)
        
        # Here you can use change_info['oldstage'] and change_info['newstage'] if 'changeInfo' is sent (otherwise you'll get a KeyError)
        
        instance.save()
        
        return instance

Как упоминалось в комментариях, поле SerializerMethod является хорошим способом:

serializers.py

class LogSerializer(...):

    ...
    changeInfo = serializers.SerializerMethodField()

    def get_changeInfo(self, obj): return {
        "leadId" : obj.lead_id,
        "updateTime": obj.update_time
    }

    class Meta:
        fields = ["changeInfo", ...]
        ...
Вернуться на верх