首页 > 解决方案 > Django Rest Framework 多张图片上传:需要一个字典,但得到了 InMemoryUploadedFile

问题描述

我正在尝试创建一个 API 来为每个会话上传多个图像,我正在使用 Django REST 框架。这是我在 Postman 中遇到的错误:

{
    "images": {
        "0": {
            "non_field_errors": [
                "Invalid data. Expected a dictionary, but got InMemoryUploadedFile."
            ]
        }
    }
}

带有 2 个表的models.py

class PostSession(models.Model):
    class Meta:
        verbose_name = 'session'
        verbose_name_plural = 'sessions'

    name = models.CharField(
        max_length=255,
    )


class PostImage(models.Model):
    class Meta:
        verbose_name = 'photo'
        verbose_name_plural = 'photos'

    name = models.ForeignKey(
        to=PostSession,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
    )
    file = models.ImageField(
        upload_to='photos',
    )

序列化程序.py

class PostImageRetrieveSerializer(serializers.ModelSerializer):

        class Meta:
            model = PostImage
            fields = '__all__'


class PostImageUpdateSerializer(serializers.Serializer):
    """
    This class for validate and save child items purpose
    """
    name = serializers.CharField(required=False, allow_null=True, allow_blank=True, )
    file = serializers.ImageField(required=True, allow_null=False, allow_empty_file=False, )

    def create(self, validated_data):
        session_name = validated_data.get('name')
        image_file = validated_data.get('file')

        if session_name and isinstance(session_name, str):
            session, _ = PostSession.objects.get_or_create(name=session_name, )
        else:
            session = None

        instance = PostImage.objects.create(
            name=session,
            file=image_file,
        )
        return self.update(
            instance=instance,
            validated_data=validated_data,
        )

    def update(self, instance, validated_data):
        instance.save()
        return instance


class PostUploadSerializer(serializers.Serializer):

    images = serializers.ListField(
        child=PostImageUpdateSerializer(required=True, allow_null=False, many=False, ),
        required=True,
        allow_null=False,
        allow_empty=False,
    )

    def validate(self, attrs):
        images_list = attrs.get('images')
        if not isinstance(images_list, list):
            raise exceptions.ValidationError(detail={
                'images': ['`images` field must be a list of dict object!', ],
            })

        return attrs

    def save_many(self):
        images_list = self.validated_data.get('images')
        post_image_instances = []

        for image_obj in images_list:
            try:
                post_image_serializer = PostImageSerializer(
                    context=self.context,
                    data=image_obj,
                    many=False,
                )
                post_image_serializer.is_valid(raise_exception=True, )
                post_image = post_image_serializer.save()
                post_image_instances.append(post_image)
            except:
                # TODO: Remove previous saved instances if needed (inside `post_image_instances`)?
                pass

        return post_image_instances

    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass

视图集.py

class PostViewSet(viewsets.GenericViewSet):
    parser_classes = [parsers.MultiPartParser, parsers.JSONParser, ]
    serializer_class = PostImageRetrieveSerializer
    queryset = PostImage.objects.all()

    @action(methods=['POST', ], detail=False, serializer_class=PostUploadSerializer, )
    def upload_images(self, request, *args, **kwargs):
        upload_serializer = PostUploadSerializer(
            context={'request': request, },
            data=request.data,
            many=False,
        )
        upload_serializer.is_valid(raise_exception=True, )
        post_image_instances = upload_serializer.save_many()

        serializer = self.get_serializer(
            post_image_instances,
            many=True,
        )
        return response.Response(
            data=serializer.data,
            status=status.HTTP_200_OK,
        )

这个想法是 API 可以创建一个包含多个图像的会话。

https://gist.github.com/cokelopez/a98ee5569991b6555ecd216764c193ec

标签: djangodjango-rest-framework

解决方案


推荐阅读