【问题标题】:TypeError: Object of type ManyRelatedManager is not JSON serializable in django rest frameworkTypeError:ManyRelatedManager 类型的对象在 django rest 框架中不是 JSON 可序列化的
【发布时间】:2021-12-03 21:34:07
【问题描述】:

我正在尝试使用他们的 id 作为主键将一些学生添加到教师班,但我遇到了错误。

我有这样的教师和学生模型。

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

这里的教师模型可以有许多学生在一个班级中使用他们的 id。我已经使用put api调用一键将学生添加到老师。

我的看法:

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)

我的序列化器:

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

这里我使用了students_in_class 作为pk 字段(我仍然不明白什么时候使用integarfield 以及什么时候使用pk 字段)。我知道,因为我将 id 添加到 student_in_class 字段中,所以我不应该将其用作 read_only = true,但是我必须使用它,否则它会产生错误。如何解决这个问题?另外,我真的不知道在序列化程序类中定义哪些字段。

更新代码:

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

【问题讨论】:

  • 请不要插入“EDIT”s/“UPDATE”s,只是让您的帖子成为编辑时最好的演示文稿。但是--请不要以使合理答案帖子无效的方式编辑问题帖子;如果有合理的答案,则修复旧帖子以提出问题并发布新问题。不要将答案编辑到问题帖子中,发布答案。 PS这篇文章没有说明这个“更新的代码”与你提出的问题有什么关系。 How to AskHelp center

标签: django api django-rest-framework primary-key django-serializer


【解决方案1】:

以下代码有效:

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

【讨论】:

    【解决方案2】:

    由于您使用的是 m2m 字段,因此您需要 students_in_class 的 ID 列表。所以解决方案将是这样的。 (免责声明:代码未经测试)。

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

    序列化错误将得到解决,因为现在您已包含 students_in_class.all 作为源。您需要通过以下方式访问数据:validated_data['students_in_class']['all']

    如果您想以不同的方式序列化您的输出,您可以将students_in_class 设置为write_only 并根据需要覆盖序列化器表示。:

    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
    

    【讨论】:

    • 我已经更新了答案。
    • 我收到错误提示 TypeError: Field 'id' expected a number but got {'all': []}。在尝试了你的代码之后......你能看看
    • 显示更新后的代码。
    • 现在请记住,您应该在 valid_data[students_in_class]['all'] 中获取对象列表。相应地修改您的代码。
    • 您好,我更新了代码,您可以检查一下吗?
    猜你喜欢
    • 2021-06-18
    • 2020-07-05
    • 2019-09-28
    • 1970-01-01
    • 2022-07-01
    • 2023-01-10
    • 2019-04-29
    • 2017-08-13
    • 1970-01-01
    相关资源
    最近更新 更多