Handle MultipleUpload file uploads with Django using
request.FILES and function-based views.
This guide covers both standard multipart uploads and chunked uploads.
pip install django django-cors-headers
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
# 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"),
]
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,
})
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})
Both endpoints must return this JSON structure on successful upload completion.
{
"success": true,
"fileGuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"fileName": "photo.jpg",
"fileSize": 204800
}
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>