Django REST Framework实现无固定键字典结构Payload的Serializer
问题原因
你之前在外层序列化器中定义了固定字段test,相当于要求Payload顶层结构必须包含test键,和你实际顶层直接以UUID为键的字典结构不匹配,所以需要去掉固定字段定义,直接对整个顶层字典做校验。
实现方案
首先确认你定义的内部操作序列化器是正确的,你之前的代码里有笔误:DictField的child参数引用了不存在的RelationshipAuthorizeObjectSerializer,替换为你定义的UserOperationSerializer即可。
你可以根据需求选择以下两种实现方式:
方式1:直接在视图层校验(无需额外定义外层序列化器)
适合仅在单个视图使用的场景:
import uuid from rest_framework import serializers from rest_framework.views import APIView from rest_framework.response import Response # 内部操作对象序列化器保持不变 class UserOperationSerializer(serializers.Serializer): operation = serializers.ChoiceField(choices=["Create", "Delete"]) operationId = serializers.UUIDField() user = serializers.CharField() immediate = serializers.BooleanField() class YourOperationView(APIView): def post(self, request): # 定义顶层字典校验规则:值为UserOperation结构 top_level_serializer = serializers.DictField( child=UserOperationSerializer() ) # 校验输入 validated_data = top_level_serializer.run_validation(request.data) # 可选:额外校验所有键为合法UUID for key in validated_data.keys(): try: uuid.UUID(key) except ValueError: raise serializers.ValidationError(f"键{key}不是合法UUID格式") # 后续业务逻辑 return Response(validated_data)
方式2:封装为可复用的独立序列化器
适合多处复用的场景,自定义顶层序列化器的校验逻辑:
import uuid from rest_framework import serializers class UserOperationSerializer(serializers.Serializer): operation = serializers.ChoiceField(choices=["Create", "Delete"]) operationId = serializers.UUIDField() user = serializers.CharField() immediate = serializers.BooleanField() class UserOperationsSerializer(serializers.Serializer): # 不需要定义任何固定字段,重写校验逻辑直接处理整个输入字典 def to_internal_value(self, data): op_serializer = UserOperationSerializer() validated_result = {} for key, op_data in data.items(): # 校验键为合法UUID try: uuid.UUID(key) except ValueError: raise serializers.ValidationError({key: "不是合法的UUID格式"}) # 校验值的结构 validated_op = op_serializer.run_validation(op_data) validated_result[key] = validated_op return validated_result
使用方式和普通序列化器完全一致:
serializer = UserOperationsSerializer(data=request.data) serializer.is_valid(raise_exception=True) # 校验通过后的数据可以直接通过validated_data获取 validated_data = serializer.validated_data
注:DRF原生
BooleanField默认支持解析字符串格式的"true"/"false",你Payload中传入的字符串类型布尔值不需要额外做转换处理。
内容的提问来源于stack exchange,提问作者user2880391
相关产品推荐
相关产品推荐

