如何在Django Rest Framework中正确获取POST请求的请求体
解决Django REST Framework中嵌套JSON请求体解析问题
问题核心
你遇到的问题本质是请求头未正确配置,导致Django REST Framework(DRF)没有将请求体解析为嵌套Python字典,而是按表单数据处理,同时dict(request.data)的操作破坏了嵌套数据结构,引发遍历错误。
解决方案
1. 确保请求头正确设置
前端发送POST请求时,必须将Content-Type设为application/json。如果缺少这个头,DRF会默认按表单数据解析请求体,嵌套的JSON层级会被拆解为扁平键值对,无法保留原结构。
2. 直接使用request.data(无需转dict)
当请求头配置正确时,DRF会自动将JSON请求体解析为Python字典,你可以直接通过request.data访问嵌套字段,不需要额外转换。
3. 用DRF序列化器验证数据(推荐)
手动解析嵌套结构容易出错,建议用DRF序列化器定义请求体结构,自动完成格式验证和数据解析,同时提供清晰的错误提示。
修改后的代码示例
基础修复版本
from django.http import JsonResponse from rest_framework.views import APIView class TestCheckView(APIView): def post(self, request, pk): result = Result() # 直接使用解析后的request.data test_id = request.data.get("id") questions = request.data.get("questions", []) for question in questions: # 提前校验数据格式 if not isinstance(question, dict): return JsonResponse({"error": "无效的问题格式"}, status=400) answers = question.get("answers", []) for answer in answers: if not isinstance(answer, dict): return JsonResponse({"error": "无效的答案格式"}, status=400) result.total += 1 # 用filter避免DoesNotExist异常 if Answer.objects.filter(id=answer["id"], question_id=question["id"]).exists(): result.score += 1 result.test = Test.objects.get(id=test_id) result.save() return JsonResponse({"status": "success"})
推荐的序列化器版本
先定义序列化器:
from rest_framework import serializers class AnswerSerializer(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(required=False) is_right = serializers.BooleanField(required=False) class QuestionSerializer(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(required=False) answers = AnswerSerializer(many=True) class TestRequestSerializer(serializers.Serializer): id = serializers.IntegerField() title = serializers.CharField(required=False) questions = QuestionSerializer(many=True)
再修改视图:
class TestCheckView(APIView): def post(self, request, pk): serializer = TestRequestSerializer(data=request.data) # 自动验证请求体格式 if not serializer.is_valid(): return JsonResponse(serializer.errors, status=400) valid_data = serializer.validated_data result = Result() test_id = valid_data["id"] for question in valid_data["questions"]: for answer in question["answers"]: result.total += 1 if Answer.objects.filter(id=answer["id"], question_id=question["id"]).exists(): result.score += 1 result.test = Test.objects.get(id=test_id) result.save() return JsonResponse({ "status": "success", "score": result.score, "total": result.total })
额外注意事项
- 避免使用
Answer.objects.get(),若记录不存在会抛出DoesNotExist异常,改用filter().exists()更安全。 - 如果请求体确实是JSON但解析失败,可手动兜底解析:
import json try: data = json.loads(request.body) except json.JSONDecodeError: return JsonResponse({"error": "无效的JSON格式"}, status=400)
内容的提问来源于stack exchange,提问作者Zor
相关产品推荐
相关产品推荐

