Django接收嵌套JSON需手动解析request.body并校验,推荐用DRF Serializer处理多层嵌套;解析前应限制深度防递归,保存时须拆解嵌套数据再分别创建模型实例。

接收嵌套JSON时request.body为空或报错
前端用 fetch 或 axios 发送 Content-Type: application/json 请求时,Django 默认不自动解析 request.body。直接读 request.POST 会是空的,因为 POST 只处理表单编码(application/x-www-form-urlencoded 或 multipart/form-data)。
正确做法是手动解析原始 body:
import json
<p>def my_view(request):
if request.method == 'POST':
try:
data = json.loads(request.body.decode('utf-8'))
except json.JSONDecodeError:
return JsonResponse({'error': 'Invalid JSON'}, status=400)</p>注意点:
-
request.body是 bytes,必须用.decode('utf-8')转成字符串再解析 - 别用
request.POST.get('xxx')——它对 JSON 请求完全无效 - 生产环境建议加
if not request.content_type == 'application/json'做类型校验
用Django REST Framework的Serializer校验嵌套结构
手写 json.loads + 手动字段校验容易漏边界、难复用。DRF 的 Serializer 是更健壮的选择,尤其对多层嵌套(如 {'user': {'profile': {'tags': ['a','b']}}})。
立即学习“Python免费学习笔记(深入)”;
示例:定义支持三级嵌套的序列化器
from rest_framework import serializers <p>class TagSerializer(serializers.Serializer): name = serializers.CharField(max_length=20)</p><p>class ProfileSerializer(serializers.Serializer): nickname = serializers.CharField(required=False) tags = TagSerializer(many=True, required=False)</p><p>class UserSerializer(serializers.Serializer): email = serializers.EmailField() profile = ProfileSerializer(required=False)</p>
在视图中使用:
HISUI 前端框架基础开发指南。HISUI 是基于 easyui 二次开发的 jQuery UI 组件库,专为医疗信息系统设计。当涉及 HISUI 组件开发、jQuery easyui 表格/表单/布局/窗口、医疗系统前端页面编写时使用此 skill。 涵盖 40 个组件的官方文档参考,支持声明式与编程式两种初始化方式,提供 $cm/$m 数据访问方法。
serializer = UserSerializer(data=data)
if serializer.is_valid():
validated_data = serializer.validated_data # 已清洗、类型转换、嵌套展开
else:
return Response(serializer.errors, status=400)
关键细节:
-
many=True用于列表字段,否则嵌套数组会校验失败 - 嵌套
Serializer默认要求非空;加required=False才允许字段缺失 -
validated_data是字典,不是模型实例——适合纯数据处理场景
避免递归嵌套导致的无限循环或性能崩塌
前端可能传入意外的深层嵌套(比如 10 层嵌套对象),或故意构造循环引用({"a": {"b": {...}}} 中 b 指回 a)。DRF 默认不检测循环,json.loads 会直接报 RecursionError 或卡死。
防御措施:
- 在解析前限制嵌套深度:
json.loads(request.body, parse_constant=lambda x: _raise_on_deep(x, max_depth=5))(需自定义钩子) - 更简单:用
json.loads的object_hook统计层级,超限时抛异常 - DRF 中可在
to_internal_value方法里加深度检查,例如len(str(data)) > 1024*100快速拦截超大 payload - Nginx 层加
client_max_body_size 2m;防止巨量 JSON 打满内存
保存嵌套数据到Django模型时的常见陷阱
拿到校验后的 validated_data 后,不能直接 User.objects.create(**validated_data)——因为 profile 是字典,不是 Profile 实例,Django 会报 Object of type dict is not JSON serializable 或字段不匹配。
正确拆解方式:
# 先 pop 出嵌套部分
profile_data = validated_data.pop('profile', None)
user = User.objects.create(**validated_data)
<p>if profile_data:
Profile.objects.create(user=user, **profile_data)</p>注意点:
- 用
.pop()而非.get(),避免把嵌套 dict 当作字段传给create() - 外键关联(如
user=user)必须显式传入,不能靠字段名自动推导 - 如果嵌套中含多对一关系(如多个
Tag),需循环创建并关联,不能用**解包
嵌套层级越深,手动拆解越容易出错;复杂业务建议封装成 save_nested() 工具函数,但别过度抽象——多数项目两层嵌套已足够。

















