Django Rest Framework使用序列化器一次上传多个图像

时间:2016-08-26 09:47:30

标签: python django image rest file-upload

我在网上针对DRF上的这个问题进行了一些研究。当一个图像在后期DRF工作得很好。但是当一个帖子中有3或5个图像时,Django只保存POST查询中的第一个图像而其他图像不保存在数据库中。 问题是如何在一个帖子中正确处理多个图像上传。

描述

  

Django版

  • 1.10
  

Rest框架版

  • 3.4.6
  

Python版

  • 3.5

这是我的代码,我试图做的是:

模型

class UserModel(AbstractEmailUser):
    first_name = models.CharField(max_length=30, db_index=True)
    last_name = models.CharField(max_length=50, db_index=True)
    details = JSONField(null=True, blank=True, db_index=True)
    avatar = models.ImageField(blank=True, null=True, upload_to='avatar')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.email)

class UserImages(models.Model):
    image = models.ImageField(upload_to='images', db_index=True)
    user = models.ForeignKey('UserModel',related_name='user')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.user)

在模型中,我有从User到UserImages的相关字段。出于POST邮件查询的目的,我手动添加用户ID以处理FK。

串行

class SerializerUserImages(serializers.ModelSerializer):

    class Meta:
        model = UserImages

    def create(self, validated_data):
        imgs = UserImages.objects.create(**validated_data)
        return imgs

也许在这里我必须做一些for循环来完成乘法图像的保存方法。

的观点

class UploadImages(APIView):
    authentication_classes = (JSONWebTokenAuthentication,)

    @parser_classes((FormParser, MultiPartParser, FileUploadParser))
    def post(self, request, format=None):

        serializer = SerializerUserImages(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(data={"msg": serializer.data}, status=status.HTTP_200_OK)
        else:
            return Response(data={"msg": serializer.errors}, status=status.HTTP_406_NOT_ACCEPTABLE)

包含所有解析器以处理此帖子查询。

这是 request.data = <QueryDict: {'image': [<InMemoryUploadedFile: top_20_cro.png (image/png)>, <InMemoryUploadedFile: images.jpg (image/jpeg)>], 'user': ['2', '2']}>

的输出

这是来自POSTMAN的请求POST的副本:

POST /api/images/ HTTP/1.1
Host: 127.0.0.1:8000
Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJvcmlnX2lhdCI6MTQ3MjIwMTcwMSwiZXhwIjoxNDcyMjMxNzAxLCJ1c2VyX2lkIjoyLCJlbWFpbCI6Im1hcmluLmJyZWthbG9AZ21haWwuY29tIiwidXNlcm5hbWUiOiJtYXJpbi5icmVrYWxvQGdtYWlsLmNvbSJ9.Fi3kmXJ44E_qhHHioniQ-cqri-u2ELU-XmpE_1oJ4Fk
Cache-Control: no-cache
Postman-Token: 1e53ac06-ed37-ff6e-2dc5-117976b86a5e
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="image"; filename=""
Content-Type: 


------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="user"

2
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="filename"

image
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="user"

2
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="filename"

image
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="image"; filename=""
Content-Type: 


------WebKitFormBoundary7MA4YWxkTrZu0gW--

如果没有一些伟大的魔法,如何处理这个问题,是否有一些我错过的简单逻辑。

3 个答案:

答案 0 :(得分:0)

尝试为图片设置文件名,我的意思是用filename=""filename="image-1"等替换filename="image-2"。文件应该有不同的文件名,或者它们互相覆盖。

答案 1 :(得分:0)

只需添加

many=True

使用序列化程序初始化程序。例如:

serializer = SerializerUserImages(data=request.data, many=True)

这应该可以解决问题。

另请查看ListSerializers

答案 2 :(得分:0)

好的,这是我对这个问题的一些逻辑,所以我希望有人会为此目的使用这个代码(hack):

序列化程序更改

class SerializerTest(serializers.Serializer):
    image = serializers.ListField(child=serializers.ImageField(required=True))


    def create(self, validated_data):

        for attr, value in validated_data.items():
            if attr == 'image':
                for x in value:
                    c = UserImages.objects.create(image=x, user_id=UserModel.objects.get(id=self.context['request'].user.id).id)
                    c.save()
        return validated_data

我已经为一个字段 img 更新了我的序列化器。并使用for循环从POST中提取图像。正如您所见,我调用查询将图像存储到FK用户的数据库中。这项工作非常好。

浏览

class UploadImages(APIView):
    authentication_classes = (JSONWebTokenAuthentication,)

    @parser_classes((FormParser, MultiPartParser, FileUploadParser))
    def post(self, request, format=None):



        serializer = SerializerTest(data=request.data, context={'request':request})

        if serializer.is_valid():
            serializer.save()
            if len(serializer.data['image']) > 0:
                que = UserImages.objects.filter(user=request.user.id)
                ser = SerializerUserImages(que, many=True)
                return Response(data={"msg": ser.data}, status=status.HTTP_200_OK)
            else:
                return Response(data={"msg": 'Provide images!'}, status=status.HTTP_406_NOT_ACCEPTABLE)
        else:
            return Response(data={"msg": serializer.errors}, status=status.HTTP_406_NOT_ACCEPTABLE)