11

I am able to upload a single image with the following code. If I select multiple images then only the last image among the selected image is getting uploaded.

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'
    )

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)


I am a little new to Django. I want to loop over my array of images which is received in the request.data Can anyone tell me how to do it?

uneet7
  • 2,925
  • 7
  • 24
  • 41

3 Answers3

22

So I finally got a workaround in my own way falling back to the basics as I didn't find any way to do it in a DRF way. I hope this answer is helpful to the Django community. I kept my model and serializers same changing the views to iterate over every image and save it using the serializer.

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'
        )

The request comes in the form of querydict. The line images = dict((request.data).lists())['image'] coverts query dict to python dict and then looping over the array under the 'image' key.

The postman request looks like below:

enter image description here Posts images to the media folder of file system

Adithya
  • 1,688
  • 1
  • 10
  • 18
uneet7
  • 2,925
  • 7
  • 24
  • 41
  • Could you please share your form data structure you sending to Django API? I am in a similar problem and can't get it to work... – Limeran Apr 15 '20 at 14:10
  • I have fully described it in question as well as the answer. Go through it throughly – uneet7 Apr 16 '20 at 15:38
  • @uneet7 How to retrieve the images as a list like `["img1.png", "img2.png"]` Instead of a list of objects like `[ {"property_id":"1", "image":"img1.png"}, {"property_id":"2", "image":"img2.png"}]` ? – Magicoder May 24 '20 at 06:47
  • Instead of using `flag` variable, please consider using `serializer.is_valid(raise_exception=True)` (notice that the if is not needed here) – kczan Jun 14 '21 at 12:56
1

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'
        )

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!',
        })    
-1

Solution for you should be using ListCreateAPIView. You dont have to implement your own view and handle everything.

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)
Kamil Niski
  • 4,580
  • 1
  • 11
  • 24