Get separate serializer response for each nested serializer

Stuck with serializer where I need to have serialized response based on the nested serializer.

Models.py :

class Parent(models.Model):
    name = models.CharField(max_length=50)

class Child(models.Model):
    parent = models.ForeignKey(Parent, related_name='children')
    child_name = models.CharField(max_length=80)

Serialziers.py

class ChildSerializer(serializers.ModelSerializer):
    class Meta:
        model = Child
        fields = '__all__'

class ParentSerializer(serializers.ModelSerializer):
    child = serializers.SerializerMethodField()
    
    def get_child(self, obj):
        childs = Child.objects.filter(parent=obj)
        return ChildSerializer(childs, many=True).data

    class Meta:
        model = Parent
        fields = '__all__'

I am getting output like below where I am getting nested childs:

{
    id : 1,
    name : "Parent1",
    child: [
        0: {id : 1, child_name : "child1"}
        1: {id : 2, child_name : "child2"}
    ]
}

But for some business purpose I need output to be something like below, where serializer should be based on child. i.e. for each child there should be separate Parent serializer. Doesn't matter if it has same id and other fields. :

{
    0:{
        id : 1,
        name : "Parent1",
        child: [
            0: {id : 1, child_name : "child1"}
        ]
    }
    1:{
        id : 1,
        name : "Parent1",
        child: [
            0: {id : 2, child_name : "child2"}
        ]
    }
}

Also please let me know if I can filter based on the child serializer. i.e. childs I will be passing to Parent serializer and get response for each childs.

Upvotes: 0

Views: 1220

Answers (2)

I directly passed the childs object in the parent serializer and filtered based on it. That did the trick for me.

class ChildSerializer(serializers.ModelSerializer):
    class Meta:
        model = Child
        fields = '__all__'

class ParentSerializer(serializers.ModelSerializer):
    name = serializers.ReadOnlyField(source='parent.name')
    child = serializers.SerializerMethodField()
    
    def get_child(self, obj):
        childs = Child.objects.filter(id=obj.id)
        return ChildSerializer(childs, many=True).data

    class Meta:
        model = Parent
        fields = ("childs", "name")

and then directly passed the child object in parent.

child = Child.objects.all()
ParentSerializer(child, many=True)

Upvotes: 1

syq
syq

Reputation: 21

Try changing the Parent Serializer as below.

class ParentSerializer(serializers.ModelSerializer):

    children = ChildSerializer(read_only=True)

    def to_representation(self, instance):
        child_query = Child.objects.filter(parent=instance)
        num_childs = child_query.count()
        ret_instance = {}
        for idx in range(num_childs):
            children = ChildSerializer(child_query[idx:idx + 1], many=True).data
            for child in children:
                child.pop('parent', None)
            temp_dict = {
              'id': instance.id,
              'name': instance.name,
              'child': children
            }
            ret_instance[idx] = temp_dict
        return ret_instance 

    class Meta:
        model = Parent
        fields = '__all__'

To change representation of serializer response, to_representation() method would need to be used.

Upvotes: 0

Related Questions