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

如何在Django Rest Framework中移除JSONField内的多余非指定键

DRF中限制JSONField内部键的实现方案

针对你需要拦截data字段内额外未知键、同时保留三个指定键可选的需求,有两种常用的原生实现方式,不需要依赖第三方库。

方案1:自定义字段级校验(轻量无需嵌套序列化器)

适合不需要复用校验逻辑的场景,直接在主序列化器里针对data字段写专属校验,代码简洁易维护。

# 预先定义允许的data内部键集合
ALLOWED_DATA_KEYS = {"item", "quantity", "cost"}

class ThingsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Things
        fields = ["id", "data"]
        extra_kwargs = {
            # 显式设置data字段非必填,匹配模型默认值逻辑
            "data": {"required": False}
        }

    def validate_data(self, value: dict) -> dict:
        # 提取前端传入的data包含的所有键
        input_keys = set(value.keys())
        # 计算超出允许范围的额外键
        extra_keys = input_keys - ALLOWED_DATA_KEYS
        if extra_keys:
            raise serializers.ValidationError(f"data字段不允许存在额外键:{', '.join(extra_keys)}")
        
        # 可选:同步校验每个允许键的类型是否符合预期
        if "item" in input_keys and not isinstance(value["item"], str):
            raise serializers.ValidationError("item必须为字符串类型")
        if "quantity" in input_keys and not isinstance(value["quantity"], str):
            raise serializers.ValidationError("quantity必须为字符串类型")
        if "cost" in input_keys and not isinstance(value["cost"], int):
            raise serializers.ValidationError("cost必须为整数类型")
        
        return value

方案2:使用嵌套序列化器约束结构(规范可复用)

如果后续data字段的结构逻辑会在其他接口复用,或者后续会扩展更复杂的嵌套校验,单独定义data的序列化器复用性更强。
首先定义专门处理data结构的序列化器,同时加校验拦截额外键:

ALLOWED_DATA_KEYS = {"item", "quantity", "cost"}

class DataStructureSerializer(serializers.Serializer):
    # 三个键都设置为非必填,匹配需求
    item = serializers.CharField(required=False)
    quantity = serializers.CharField(required=False)
    cost = serializers.IntegerField(required=False)

    def validate(self, attrs):
        # 获取前端传入的原始data的所有键
        input_keys = set(self.initial_data.keys())
        extra_keys = input_keys - ALLOWED_DATA_KEYS
        if extra_keys:
            raise serializers.ValidationError(f"data字段不允许存在额外键:{', '.join(extra_keys)}")
        return attrs

然后在主序列化器里直接用这个嵌套序列化器替换默认的JSONField:

class ThingsSerializer(serializers.ModelSerializer):
    # 用自定义的嵌套序列化器作为data字段的类型,设置非必填
    data = DataStructureSerializer(required=False)

    class Meta:
        model = Things
        fields = ["id", "data"]

两种方案逻辑一致,可根据是否需要复用data结构校验逻辑自行选择。

注意事项

  • DRF默认反序列化时,对未在序列化器中声明的字段是静默忽略的,不会主动报错,所以必须手动加入额外键的校验逻辑才能达到拦截效果。
  • 如果不需要对额外键报错,仅希望过滤掉额外键,可以在校验时把允许的键提取出来重新赋值给value返回,不需要抛出错误。
  • 校验逻辑会在反序列化(创建/更新对象)时自动触发,不需要额外在视图里写调用逻辑。

内容的提问来源于stack exchange,提问作者Puneet Garg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 01:24:04