Home > Software engineering >  TypeError: Object of type ManyRelatedManager is not JSON serializable in django rest framework
TypeError: Object of type ManyRelatedManager is not JSON serializable in django rest framework

Time:10-17

I am trying to add some students to a teacher class using their ids as primary key but I am getting above error.

I have models of Teachers and Students like this.

class Student(TimeStampAbstractModel):
    user = models.OneToOneField(User, related_name="student", on_delete=models.CASCADE)
    college_name = models.CharField(max_length=255, default="", blank=True)
    address = models.CharField(max_length=255, default="", blank=True)

    def __str__(self):
        return self.user.name

class Teacher(TimeStampAbstractModel):
    user = models.OneToOneField(User, related_name="teacher", on_delete=models.CASCADE)
    address = models.CharField(max_length=255, default="", blank=True)
    students_in_class = models.ManyToManyField(Student,related_name="teacher")

    def __str__(self):
        return self.user.name

Here a teacher model can have many students in a class with thier ids. I have used an put api call to add the students to the teacher in one click.

My view:

from rest_framework import status
class AddtoClassView(APIView):
    

    def put(self,request,pk,*args,**kwargs):
        id =pk
        teacher = Teacher.objects.get(id=id)
        serializer = TeacherSerializer(teacher,data=request.data)
        if serializer.is_valid():
            serializer.save()
            print("iam if")
            return Response({
                "message":"Student has been added to class.",
                "data": serializer.data
            },status=status.HTTP_200_OK)

        # else:
        print("iam else")
        return Response(serializer.data)

My serializer:

class TeacherSerializer(serializers.ModelSerializer):
    students_in_class = serializers.PrimaryKeyRelatedField(
        read_only= True
    )
    address = serializers.CharField(required=False)
    # user = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = Teacher
        fields = ["address","students_in_class"]
        # fields = '__all__'

    def update(self, instance, validated_data):
        instance.address = validated_data.get("address")
        instance.save()
        stu = validated_data.get("students_in_class")
        print(stu)
        if stu is not None:
            print("iam stu")
            instance.students_in_class.add(stu)
        instance.save()
        super(TeacherSerializer,self).update(instance, validated_data)
        return instance

Here I have used students_in_class as pk field ( i still havent understand when to use integarfield and when to use pk field). I know since i am adding the ids to the student_in_class field i am not supposed to use it as read_only = true, however i had to use otherwise it generates error. How to solve this? Also, i dont really know which fields to define as which in serializer class.

Updated code:

class TeacherSerializer(serializers.ModelSerializer):
    # students_in_class = serializers.PrimaryKeyRelatedField(
    #     many = True, read_only= True
    # )
    students_in_class = serializers.ListField(
        source="students_in_class.all",
        child=serializers.PrimaryKeyRelatedField(queryset=Student.objects.all()),
    )
    address = serializers.CharField(required=False)
    # user = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = Teacher
        fields = ["address","students_in_class"]
        # fields = '__all__'

    def update(self, instance, validated_data):
        instance.address = validated_data['students_in_class']['all']
        instance.save()
        stu = validated_data.get("students_in_class")
        print(stu)
        if stu is not None:
            print("iam stu")
            instance.students_in_class.add(stu)
        instance.save()
        super(TeacherSerializer,self).update(instance, validated_data)
        return instance

CodePudding user response:

Since you are using m2m field, you need list of ids for students_in_class. So the solution will be something like this. (Disclaimer: Code not tested).

class TeacherSerializer(serializers.ModelSerializer):
    students_in_class = serializers.ListField(
        source="students_in_class.all", 
        child=serializers.PrimaryKeyRelatedField(queryset=Student.objects.all()),
    )

Serialization error will be solved because now you have included students_in_class.all as source. You need to access the data with something like this: validated_data['students_in_class']['all']

If you want to serialize your output in different way, you could set students_in_class as write_only and override serializer representation as needed.:

class TeacherSerializer(serializers.ModelSerializer):
    students_in_class = serializers.ListField(
        child=serializers.PrimaryKeyRelatedField(queryset=Student.objects.all()),
        write_only=True
    )
    # your code

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret['students_in_class'] = StudentSerializer(instance.students_in_class.all(), many=True).data
        return ret

CodePudding user response:

The following code worked:

class TeacherSerializer(serializers.ModelSerializer):
    students_in_class = serializers.PrimaryKeyRelatedField(
        many = True,queryset=Student.objects.all()
    )
    address = serializers.CharField(required=False)

    class Meta:
        model = Teacher
        fields = ["address","students_in_class"]


    def update(self, instance, validated_data):
        instance.address = validated_data.get("address")
        instance.save()
        stu = validated_data.pop("students_in_class")

        for stus in stu:
            instance.students_in_class.add(stus)

        instance.save()
        super(TeacherSerializer,self).update(instance, validated_data)
        return instance
  • Related