DRF - 嵌套的序列化程序在父调用is_valid()后消失

时间:2017-12-11 20:09:54

标签: python django django-rest-framework

TLDR; (完整描述如下)

验证父序列化程序时会删除嵌套序列化程序的有效字段。我读了一些类似案例的StackOverflow帖子,但由于read_only=True而不是我的CreateParentView(generics.CreateAPIView)字段被删除了案件。

将有效对象发布到Http 400 Bad request后,出现create()错误。我最终调试了# parsed_data is a QueryDict prepared from request.POST and request.FILES # to fit the nested serializers format. -> serializer.is_valid(raise_exception=True) (Pdb) parsed_data.keys() odict_keys(['parent_field_1', 'parent_field_2', 'parent_field_3', 'child']) (Pdb) from .serializers import CreateChildSerializer; ch = parsed_data.get('child'); new_child = CreateChildSerializer(data = ch); (Pdb) new_child.is_valid() True (Pdb) new_child.errors {} # the parent serializer is invalid and drops the 'child' key (Pdb) serializer.is_valid(); False (Pdb) serializer.data.keys() odict_keys(['parent_field_1', 'parent_field_2', 'parent_field_3']) 方法。

400 (Bad Request), "{"child":["This field is required."]}"

回复是models.py Dafuq,我刚刚为你提供了这个,而你,先生,放弃了它: - (

TLDR结束;

好的,让我们来看看View,Serializer和Model。 我正在使用一个玩具模型,我的真实模型太冗长了,无法在这里重现。

让我们从Child开始 - ParentOneToOneField模型的关系为# models.py class Parent(models.Model): objects = ParentManager() user = models.ForeignKey('auth.User', on_delete=models.CASCADE) parent_field_1 = models.BooleanField() parent_field_2 = models.CharField(max_length=10) parent_field_3 = models.CharField(max_length=10) class Child(models.Model): objects = ChildManager() parent = models.OneToOneField('Parent', on_delete=models.CASCADE) child_field_1 = ...

# serializers.py    
class CreateParentSerializer(serializers.ModelSerializer):
    child = CreateChildSerializer()

    class Meta:
        model = Parent
        fields = ('parent_field_1', 'parent_field_2', 'parent_field_3', 'child')

    @transaction.atomic
    def create(self, validated_data):
        child_data = validated_data.pop('child')
        user = self.context['request'].user
        parent = Parent.objects.create(user=user, **validated_data)

        Child.objects.create(parent=parent, **child_data)

        return parent

序列化程序基本上是嵌套序列化程序的 DRF guide approach

# views.py
class CreateParentView(generics.CreateAPIView):
    serializer_class = CreateParentSerializer

    def create(self, request, *args, **kwargs):
        parsed_data = self.parse_request_data(request)

        serializer = self.get_serializer(data=parsed_data)
        import pdb; pdb.set_trace()
        serializer.is_valid(raise_exception=True)

        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def parse_request_data(self, request):
        data_dict = dict(request.data)

        # renaming keys, adding FILES to reproduce required structure, verbose and irrelevant

        parsed_data = QueryDict('', mutable=True)
        parsed_data.update(data_dict)

        return parsed_data

最后是观点。

text()

我没有想法:X

1 个答案:

答案 0 :(得分:0)

实际上,在这里张贴就像一个魅力......

我偶然发现了this GitHub线程来解决这个问题。

  

QueryDict仅用于不支持嵌套对象的多部分输入。

我必须使用FILES传输嵌套对象,因此使用了multipart / form-data并需要parse_request_data(request)方法。修改方法以返回普通dict而不是QueryDict后,一切都顺利进行。

def parse_request_data(self, request):
        data_dict = dict(request.data)

        # renaming keys, adding FILES to reproduce required structure, verbose and irrelevant

        ### parsed_data = QueryDict('', mutable=True)
        ### parsed_data.update(data_dict)

        return data_dict
相关问题