Works with any backend npm install Zero dependencies
← All Backend Guides

Django

Handle MultipleUpload file uploads with Django using request.FILES and function-based views. This guide covers both standard multipart uploads and chunked uploads.

Dependencies

pip install django django-cors-headers

Settings

Add CORS support in settings.py.

# settings.py
INSTALLED_APPS = [
    # ...
    "corsheaders",
]

MIDDLEWARE = [
    "corsheaders.middleware.CorsMiddleware",
    # ... other middleware
]

CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_HEADERS = [
    "content-type", "x-upload-id", "x-chunk-index",
    "x-chunk-count", "x-file-name", "x-file-size",
]

FILE_UPLOAD_MAX_MEMORY_SIZE = 200 * 1024 * 1024  # 200 MB
DATA_UPLOAD_MAX_MEMORY_SIZE = 200 * 1024 * 1024

URL Configuration

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path("api/upload", views.upload_file, name="upload"),
    path("api/upload-chunk", views.upload_chunk, name="upload_chunk"),
]

Multipart Form Upload

The view receives the file through Django's request.FILES dictionary and saves it with a unique GUID.

# views.py
import os
import uuid
import shutil
import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from django.conf import settings

UPLOAD_DIR = os.path.join(settings.BASE_DIR, "uploads")
CHUNK_DIR = os.path.join(UPLOAD_DIR, "chunks")
os.makedirs(UPLOAD_DIR, exist_ok=True)


@csrf_exempt
@require_POST
def upload_file(request):
    uploaded_file = request.FILES.get("file")
    if not uploaded_file:
        return JsonResponse({"success": False, "error": "No file uploaded"}, status=400)

    file_guid = str(uuid.uuid4())
    ext = os.path.splitext(uploaded_file.name)[1]
    dest_path = os.path.join(UPLOAD_DIR, file_guid + ext)

    with open(dest_path, "wb") as dest:
        for chunk in uploaded_file.chunks():
            dest.write(chunk)

    return JsonResponse({
        "success": True,
        "fileGuid": file_guid,
        "fileName": uploaded_file.name,
        "fileSize": uploaded_file.size,
    })

Chunked Upload

Each chunk arrives as a raw body with custom headers. Store chunks in a temporary directory and assemble the final file once all chunks have arrived.

@csrf_exempt
@require_POST
def upload_chunk(request):
    upload_id   = request.headers.get("X-Upload-Id", "")
    chunk_index = int(request.headers.get("X-Chunk-Index", 0))
    chunk_count = int(request.headers.get("X-Chunk-Count", 0))
    file_name   = request.headers.get("X-File-Name", "unknown")
    file_size   = int(request.headers.get("X-File-Size", 0))

    if not upload_id or not chunk_count:
        return JsonResponse({"success": False, "error": "Missing headers"}, status=400)

    session_dir = os.path.join(CHUNK_DIR, upload_id)
    os.makedirs(session_dir, exist_ok=True)

    # Save this chunk from raw body
    chunk_path = os.path.join(session_dir, f"chunk_{chunk_index}")
    with open(chunk_path, "wb") as f:
        f.write(request.body)

    # Count received chunks
    received = len([
        name for name in os.listdir(session_dir)
        if name.startswith("chunk_")
    ])

    if received == chunk_count:
        # Assemble final file
        file_guid = str(uuid.uuid4())
        ext = os.path.splitext(file_name)[1] if file_name else ""
        final_path = os.path.join(UPLOAD_DIR, file_guid + ext)

        with open(final_path, "wb") as output:
            for i in range(chunk_count):
                cp = os.path.join(session_dir, f"chunk_{i}")
                with open(cp, "rb") as chunk_file:
                    output.write(chunk_file.read())

        # Clean up chunks
        shutil.rmtree(session_dir)

        return JsonResponse({
            "success": True,
            "fileGuid": file_guid,
            "fileName": file_name,
            "fileSize": file_size,
        })

    return JsonResponse({"success": True, "chunksReceived": received})

Expected JSON Response

Both endpoints must return this JSON structure on successful upload completion.

{
  "success": true,
  "fileGuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "fileName": "photo.jpg",
  "fileSize": 204800
}

Client-Side JavaScript

Initialize MultipleUpload on the client, pointing to your Django endpoints.

<link rel="stylesheet" href="multipleupload.css" />
<div id="uploader"></div>
<script src="multipleupload.js"></script>
<script>
  var uploader = new MultipleUpload("#uploader", {
    uploadUrl: "/api/upload",
    chunkUploadUrl: "/api/upload-chunk",
    chunkSize: 2 * 1024 * 1024, // 2 MB chunks
    onFileUploaded: function (file, response) {
      console.log("Uploaded:", response.fileName, response.fileGuid);
    }
  });
</script>