You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:52:39