In django rest framework, I am able to upload single file using danialfarid/ng-file-upload

class PhotoViewSet(viewsets.ModelViewSet):
    serializer_class = PhotoSerializer
    parser_classes = (MultiPartParser, FormParser,)

    def perform_create(self, serializer):'created_at'),

class PhotoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Photo

class Photo(models.Model):
    blogs = models.ForeignKey(Blogs, related_name="blogs_img")
    image = models.ImageField(upload_to=content_file_name)

When I try to upload multiple file. I get in

chrome developer tools:
Request Payload

Content-Disposition: form-data; name="image[0]"; filename="datacable.jpg"
Content-Type: image/jpeg

Content-Disposition: form-data; name="image[1]"; filename="datacable2.jpg"
Content-Type: image/jpeg


{"image":["No file was submitted."]}

I don’t know how to write serializer for uploading multiple file.

I manage to solve this issue and I hope it will help community

class FileListSerializer ( serializers.Serializer ) :
    image = serializers.ListField(
                       child=serializers.FileField( max_length=100000,
                                         use_url=False )
    def create(self, validated_data):
        for img in image:
        return photo

class PhotoSerializer(serializers.ModelSerializer):

    class Meta:
        model = Photo
        read_only_fields = ("blogs",)

class PhotoViewSet(viewsets.ModelViewSet):
    serializer_class = FileListSerializer
    parser_classes = (MultiPartParser, FormParser,)

I dont know it very well, but this is working…
This is for my viewset.

def perform_create(self, serializer):
    obj =
    for f in'files'):
        mf = MyFile.objects.create(file=f)

It took me a while to find out an effective solution to this,
I would like to share with you what finally worked for me.
I am using reactjs and DRF.

Here is my model :

class MediaFile(models.Model):
    article = models.ForeignKey(Articles, on_delete=models.CASCADE, null=True)
    caption = models.CharField(max_length=500, null=True, blank=True)
    file = models.FileField('photo of article', upload_to=set_filename,
                            blank=True, null=True, default="")
    added = models.DateTimeField(auto_now_add=True)

The views are standard viewsets.ModelViewSet

class MediaFilesViewSet(viewsets.ModelViewSet):
    serializer_class = FileListSerializer
    parser_classes = (parsers.MultiPartParser, parsers.FormParser,)

In ArticleSerializer I added:

def create(self, validated_data):
    request = self.context.get('request')
    user = request.user
    instance = Articles.objects.create(**validated_data)
    instance.publisher = user
    images = request.FILES
    if images:
            for f in images.getlist('mediafiles'):
        except Exception as e:
    return instance

The FRONTEND structure:

postChangeImage = (event) =>{
        is_images: true
    let files =;
    const files_array = Object.values(files);

        {imagefile: files}

    console.log('IMAGES ARRAY', files_array); => {
        const urls = URL.createObjectURL(value);
            {postfolio:[urls, ...prevState.postfolio]}



for (let i=0; i< this.state.imagefile.length; i++) {
                    form_data.append(`mediafiles`, this.state.imagefile[i]);

Here is how you upload multiple files on blogs api:

class Blogs(models.Model):

class Photo(models.Model):
    blogs = models.ForeignKey(Blogs, related_name="blogs_img")
    image = models.ImageField(upload_to=content_file_name)

class PhotoSerializer(serializers.ModelSerializer):

    class Meta:
        model = Photo
        fields = ['blogs', 'image',]

class BlogsSerializer(serializers.ModelSerializer):
    photos = serializers.SerializerMethodField()

    def get_photos(self, obj):
        photos = Photo.objects.filter(blogs=obj)
        return PhotoSerializer(photos, many=True, read_only=False).data

    class Meta:
        model = Blogs
        fields = [

class BlogsViewSet(viewsets.ModelViewSet):
    serializer_class = BlogsSerializer
    queryset = Blogs.objects.all()

    def create(self, request, *args, **kwargs):
        instance_data =
        data = {key: value for key, value in instance_data.items()}
        serializer = self.get_serializer(data=data)
        instance =

        if request.FILES:
            photos = dict((request.FILES).lists()).get('photos', None)
            if photos:
                for photo in photos:
                    photo_data = {}
                    photo_data["blogs"] =
                    photo_data["image"] = photo
                    photo_serializer = PhotoSerializer(data=photo_data)

        return Response(

The best answer to this question did not work for me, but Charles’ suggestion worked very well. In my case, I needed to upload multiple files and assign them to a specific batch. Each batch is assigned to a particular user.

Below is more context using ReactJS to make the POST request, along with the serializers used and Postman window:

from convert_files.models import File
from rest_framework import viewsets, permissions
from rest_framework.parsers import MultiPartParser, JSONParser
from .serializers import BatchSerializer

class BatchViewSet(viewsets.ModelViewSet):
    permission_classes = [

    def perform_create(self, serializer):
        obj =
        for f in'files'):
            mf = File.objects.create(office_file=f)

    parser_classes = (MultiPartParser, JSONParser, )

    serializer_class = BatchSerializer

    http_method_names = ['get','post','delete','put','patch', 'head']

    def get_queryset(self):
        return self.request.user.batches.all()

from rest_framework import serializers
from convert_files.models import File, Batch

class FileSerializer(serializers.ModelSerializer):
    class Meta:
        model = File

class BatchSerializer(serializers.ModelSerializer):
    files = FileSerializer(many=True, required = False)

    class Meta:
        model = Batch

from django.db import models
from django.conf import settings
from django.contrib.auth.models import User

from .extra import ContentTypeRestrictedFileField

def make_upload_path(instance, filename):
    """Generates upload path for FileField"""
    return settings.OFFICE_OUTPUT_FILES_URL + "/%s" % (filename)

class Batch(models.Model):
    name = models.CharField(max_length=100, blank=True)
    description = models.TextField(blank=True)
    date_posted = models.DateTimeField(
    owner = models.ForeignKey(User, related_name="batches", 
                            on_delete=models.CASCADE, null=True)

class File(models.Model):
    name = models.CharField(max_length=100, blank=True)
    office_file = ContentTypeRestrictedFileField(
        upload_to           = make_upload_path,
        content_types       = ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        max_upload_size     = 10485760,

    files = models.ForeignKey(Batch, on_delete=models.CASCADE, null=True, 
                                    related_name="files", related_query_name="files")


import React, { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { addBatch } from '../actions/batches';

function FileUpload() {

  const dispatch = useDispatch();
  let formData = new FormData()

  const onDrop = useCallback((acceptedFiles) => {
    for (var i = 0; i < acceptedFiles.length; i++) {
      formData.append("files", acceptedFiles[i], acceptedFiles[i].name)



Image of POST request in Postman for Multiple File Upload to DRF

Working with “dictionary (array) of images”

Ok, so today I tried Arindam’s solution.. it worked perfectly, but after a while, I figgured out that my frontend (port 3000) makes a GET request to itself looking for an image that is not there, and not at the backend(port 8000).. (eg. GET http://localhost:3000/media/images/products/default.png – Returns 404: Not found).. What worked for me was to change the code around a bit and this is my solution..


class Product(models.Model):
    title = models.CharField(max_length=255)
    description = models.CharField(max_length=255)
    price = models.FloatField()
    quantity = models.IntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)
    active = models.BooleanField(default=False)
    slug = models.SlugField(max_length=255, unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

class ProductImage(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="images")
    image = models.ImageField("Image", upload_to=upload_to, default="products/default.png")


class ProductImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProductImage
        fields = ['id', 'image', 'product']
        extra_kwargs = {
        'product': {'required': False},

class ProductSerializer(serializers.ModelSerializer):
    images = ProductImageSerializer(many=True, required=False)

    class Meta:
        model = Product
        fields = ['id', 'title', 'description', 'images', 'price', 'quantity', 'active', 'slug', 'created_at', 'modified_at']
        read_only_fields = ['slug']
        #lookup_field = 'slug'

    def create(self, validated_data):        
        product = Product.objects.create(**validated_data)
            # try to get and save images (if any)
            images_data = dict((self.context['request'].FILES).lists()).get('images', None)
            for image in images_data:
                ProductImage.objects.create(product=product, image=image)
            # if no images are available - create using default image
        return product


class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    permission_classes = [permissions.AllowAny]
    serializer_class = ProductSerializer
    parser_classes = [MultiPartParser, FormParser]
    #lookup_field = 'slug'

edit: in

import os
BASE_DIR = Path(__file__).resolve().parent.parent
MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', "")
MEDIA_URL = '/media/'

I am posting this here to help someone (or me again in the future) with multiple files upload or multiple images upload as I spent 2 days looking up tutorials and answeres online to help me solve this issue… I may not be doing everything perfectly as I just recently started exploring Django REST Framework (and Python), but I hope it helps.

I have solved the issue with this solution

class Product(models.Model):
   title = models.CharField(max_length=255)
   description = models.CharField(max_length=255)

class Images(models.Model):
   product = model.ForeignKey('Product', related_name="images", on_delete=models.CASCADE)
   image = models.ImageField(upload_to=upload_path)

class ImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Images

class ImagesViewSet(ModelViewSet):
    queryset = models.Images.objects.all()
    serializer_class = serializers.ImageSerializer
    # overwrite create method from the CreateModelMixin
    def create(self, request, *args, **kwargs):
        data =
        images = data.getlist('image')
        # if no images call parent method it will return error
        if not images:
            return super().create(request, *args, **kwargs)

        # verify only without creating the images
        serializer_lst = []
        for image in images:
            data['image'] = image
            serializer = self.get_serializer(data=data)
        serializers_data = [] # this is to collect data for all created images and return as list in the response
        for serializer in serializer_lst:
            headers = self.get_success_headers(
        return Response(serializers_data, status=status.HTTP_201_CREATED, headers=headers)