Django嵌套序列化器PUT方法报错:QuerySet对象无answer属性
问题现象
Django REST Framework 项目中更新嵌套序列化器时抛出AttributeError,错误提示为'QuerySet' object has no attribute 'answer',对应PUT请求接口/quiz/q/django/1/返回500状态码。
核心报错栈关键片段:
File "C:\Users\HP\Desktop\roy\project\HelpMe\sunny\backend\quiz\serializers.py", line 47, in update answer = instance.answer.all() AttributeError: 'QuerySet' object has no attribute 'answer'
报错根因
一共两处代码逻辑错误:
- 视图层查询目标Question对象时使用了
filter()方法,该方法返回的是QuerySet集合(即使匹配到唯一ID的结果,也是集合类型,不是单个模型实例),传给序列化器后,序列化器update方法拿到的instance是QuerySet,自然无法访问单个实例才有的反向关联属性answer。 - 序列化器的update方法本身存在次级逻辑错误:将关联answer转成list类型后,错误地对list对象调用
.objects.get()方法,list类型没有objects属性,就算解决了前面的QuerySet问题,这里也会触发新的报错。
修复方案
1. 修改视图层代码
将查询单个实例的filter()方法替换为get_object_or_404(),既可以返回单个模型实例,也能在ID对应记录不存在时自动返回404响应,修复后的视图代码:
from django.shortcuts import get_object_or_404 from rest_framework.views import APIView from rest_framework import status from rest_framework.response import Response from .models import Question from .serializers import QuestionSerializer class QuizQuestionDetail(APIView): def get(self, request, format=None, **kwargs): quizz = get_object_or_404(Question, id=kwargs['pk']) serializer = QuestionSerializer(quizz) return Response(serializer.data) def put(self, request, format=None, **kwargs): quizz = get_object_or_404(Question, id=kwargs['pk']) serializer = QuestionSerializer(quizz, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
注意:GET接口原来传了
many=True是因为查询结果是QuerySet,改成单个实例后要去掉many=True参数,否则序列化器会把单个实例当列表处理。
2. 修改序列化器update方法
修正answer查询、更新的逻辑,不要对list类型调用ORM方法,修复后的update方法代码:
def update(self, instance, validated_data): answers_data = validated_data.pop('answer') # 先更新Question本身的字段 instance.quiz = validated_data.get('quiz', instance.quiz) instance.title = validated_data.get('title', instance.title) instance.save() # 遍历更新关联的Answer for answer_data in answers_data: # 直接通过Answer模型用id查询,不要对list调用objects方法 answer_obj = Answer.objects.get(pk=answer_data['id'], question=instance) answer_obj.answer_text = answer_data.get('answer_text', answer_obj.answer_text) answer_obj.is_right = answer_data.get('is_right', answer_obj.is_right) answer_obj.save() return instance
补充:查询Answer时加上
question=instance过滤条件,可以避免越权修改不属于当前问题的答案。
内容的提问来源于stack exchange,提问作者Efe Roy
相关产品推荐
相关产品推荐

