如何使用 DJango Rest Framework 上传多个图像?

Posted

技术标签:

【中文标题】如何使用 DJango Rest Framework 上传多个图像?【英文标题】:How to upload multiple Images using DJango Rest Framework? 【发布时间】:2019-03-24 23:41:31 【问题描述】:

我可以使用以下代码上传单个图像。如果我选择多张图片,则只有所选图片中的最后一张图片会被上传。 模型.py

class Image(models.Model):
property_id = models.ForeignKey(
                'properties.Address',
                null=False,
                default=1,
                on_delete=models.CASCADE
            )
image = models.ImageField(upload_to=directory_path)

序列化器.py

class ImageSerializer(serializers.ModelSerializer):
class Meta:
    model = Image
    fields = (
        'property_id',
        'image'
    )

views.py

class ImageView(APIView):
parser_classes = (MultiPartParser, FormParser)

def get(self, request):
    all_images = Image.objects.all()
    serializer = ImageSerializer(all_images, many=True)
    return JsonResponse(serializer.data, safe=False)

def post(self, request, *args, **kwargs):
    file_serializer = ImageSerializer(data=request.data)
    if file_serializer.is_valid():
        file_serializer.save()
        return Response(file_serializer.data, status=status.HTTP_201_CREATED)
    else:
        return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

我对 Django 有点陌生。我想遍历 request.data 中收到的图像数组,谁能告诉我该怎么做?

【问题讨论】:

试试file_serializer = ImageSerializer(data=request.FILES, many=isinstance(request.FILES, list)) 不,它不起作用。此外,它将所有图像上传到同一个属性文件夹 【参考方案1】:

所以我终于以自己的方式找到了一种解决方法,回到了基础,因为我没有找到任何方法来以 DRF 方式做到这一点。我希望这个答案对 Django 社区有所帮助。我保持我的模型和序列化程序相同,更改视图以迭代每个图像并使用序列化程序保存它。

views.py

class ImageView(APIView):
    parser_classes = (MultiPartParser, FormParser)

    def get(self, request):
        all_images = Image.objects.all()
        serializer = ImageSerializer(all_images, many=True)
        return JsonResponse(serializer.data, safe=False)

    def post(self, request, *args, **kwargs):
        property_id = request.data['property_id']

        # converts querydict to original dict
        images = dict((request.data).lists())['image']
        flag = 1
        arr = []
        for img_name in images:
            modified_data = modify_input_for_multiple_files(property_id,
                                                            img_name)
            file_serializer = ImageSerializer(data=modified_data)
            if file_serializer.is_valid():
                file_serializer.save()
                arr.append(file_serializer.data)
            else:
                flag = 0

        if flag == 1:
            return Response(arr, status=status.HTTP_201_CREATED)
        else:
            return Response(arr, status=status.HTTP_400_BAD_REQUEST)

helpers.py

def modify_input_for_multiple_files(property_id, image):
    dict = 
    dict['property_id'] = property_id
    dict['image'] = image
    return dict

models.py

class Image(models.Model):
    property_id = models.ForeignKey(
                    'properties.Address',
                    null=False,
                    default=1,
                    on_delete=models.CASCADE
                )
    image = models.ImageField(upload_to=directory_path)

serializers.py

class ImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Image
        fields = (
            'property_id',
            'image'
        )

请求以 querydict 的形式出现。 images = dict((request.data).lists())['image'] 行将查询字典转换为 python 字典,然后在 'image' 键下循环遍历数组。

邮递员请求如下所示

【讨论】:

能否分享您发送到 Django API 的表单数据结构?我遇到了类似的问题,无法正常工作... 我已经完全描述了问题以及答案。彻底看完 @uneet7 如何将图像检索为["img1.png", "img2.png"] 之类的列表而不是[ "property_id":"1", "image":"img1.png", "property_id":"2", "image":"img2.png"] 之类的对象列表? 不要使用flag变量,请考虑使用serializer.is_valid(raise_exception=True)(注意这里不需要if)【参考方案2】:

models.py

class Image(models.Model):
    property_id = models.ForeignKey(
                'properties.Address',
                null=False,
                default=1,
                on_delete=models.CASCADE
            )
    image = models.ImageField(upload_to=directory_path)

序列化器.py

class ImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Image
        fields = (
            'property_id',
            'image'
        )

views.py

class ImageAPIView(ListCreateAPIView):
    queryset = Image.objects.all()
    serializer_class = ImageSerializer
    def post(self, request, *args, **kwargs):
        property_id = request.data['property']
        form_data = 
        form_data['property']= property_id
        success = True
        response = []
        for images in request.FILES.getlist('images'):
            form_data['images']=images
            print(form_data)
            serializer = PropertyImageSerializers(data=form_data)
            if serializer.is_valid():
                serializer.save()
                response.append(serializer.data)
            else:
                success = False
        if success:
            #return Response(response, status=status.HTTP_201_CREATED)
           
            return Response(
            'status' : 1, 
            'message' : 'Success',
            'Data' : response,
            )
            
          #returnResponse(response,status=status.HTTP_400_BAD_REQUEST)

        return Response(
            'status' : 0, 
            'message' : 'Error!',
        )    

【讨论】:

【参考方案3】:

您的解决方案应该是使用ListCreateAPIView。您不必实现自己的视图并处理所有事情。

class ImageView(generics.ListCreateAPIView):
    parser_classes = (MultiPartParser, FormParser)
    queryset = Image.objects.all()
    serializer_class = ImageSerializer

    def get_serializer(self, *args, **kwargs):
        if isinstance(kwargs.get('data', ), list):
            kwargs['many'] = True
        return super(CreateListModelMixin, self).get_serializer(*args, **kwargs)

【讨论】:

@UnitPatel 可以,但基本上你将重新实现已经用 DRF 编写的代码 它还在上传单张图片。我已经更新了我的问题。你能再看看吗?

以上是关于如何使用 DJango Rest Framework 上传多个图像?的主要内容,如果未能解决你的问题,请参考以下文章

django.test.client 上的 Django rest 框架导入错误

无法使用 Django Rest 框架发送压缩的 gzip 数据

Django 和 Django 休息框架

Django前后端分离——drf

Django REST to React - 无需密码即可获取社交身份验证令牌

尽管有 AllowAny 权限,django-rest-framework 在 POST、PUT、DELETE 上返回 403 响应