Reputation: 4192
I'm wanting to know how you would pass nested data to a ModelSerializer
if the child of the nested data is not a model on its own.
The data that I'm working with looks like this:
{
'leadId': 12345,
'updateTime': 1651250096821,
'changeInfo': {
'oldstage': 'New Leads',
'newstage': 'Attempting Contact'
}
}
From previous experience, I know that if I was only working with the leadId
and the updateTime
, my serializer would look like this:
class LogSerializer(serializers.ModelSerializer):
leadId = serializers.IntegerField(source="lead_id")
updateTime = serializers.IntegerField(source="update_time")
class Meta:
model = Log
fields = ["leadId", "updateTime"]
Which would then make it possible to do this:
data = {
'leadId': 12345,
'updateTime': 1651250096821
}
serializer = LogSerializer(data=data)
serializer.is_valid()
serializer.save()
If I'm not wanting to turn changeInfo
into its own model, is it possible to map the fields to the nested data? Something that might look like this (but this obviously doesn't work):
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]
Upvotes: 0
Views: 74
Reputation: 799
You can use a custom serializer for your changeInfo
field (you don't need to create a model for that):
class ChangeInfoSerializer(serializers.Serializer):
oldstage = serializers.CharField(max_length=100, source="old_stage") # Set max_length to a value that suits your needs
newstage = serializers.CharField(max_length=100, source="new_stage")
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')
for key, value in change_info.items():
if key == "old_stage":
validated_data['old_stage'] = value
elif key == "new_stage":
validated_data['new_stage'] = value
log = Log.objects.create(**validated_data)
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
Upvotes: 1
Reputation: 3527
As mentioned in the comments, a SerializerMethodfield is a good way to go:
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", ...]
...
Upvotes: 0