如何在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
相关产品推荐
相关产品推荐

