Handling File Uploads in Django Applications

This article explains how Django processes file uploads, how uploaded files are stored in request.FILES, how to handle files manually or through models, how to save files efficiently using chunks, and how to implement multiple file uploads using custom form fields and widgets.

Django file uploadrequest.FILESFileField

~8 min read • Updated Mar 14, 2026

Introduction

When a user uploads a file in a Django application, the uploaded content is stored in request.FILES. This dictionary contains an entry for each FileField or ImageField submitted through a form. Understanding how Django handles file uploads is essential for building secure and efficient applications.


It is important to note that accepting uploaded files from untrusted users introduces security risks. Refer to Django’s security documentation on User-uploaded content for mitigation strategies.


Basic File Uploads

Consider a simple form containing a FileField:


from django import forms

class UploadFileForm(forms.Form):
    title = forms.CharField(max_length=50)
    file = forms.FileField()

When this form is submitted, the uploaded file becomes available in request.FILES. For example, the file can be accessed using request.FILES['file'].


Keep in mind that request.FILES will only contain data if:

  • The request method is POST.
  • At least one file was uploaded.
  • The form uses enctype="multipart/form-data".

Binding Uploaded Files to a Form

To process uploaded files, pass request.FILES to the form constructor:


from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
from somewhere import handle_uploaded_file

def upload_file(request):
    if request.method == "POST":
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES["file"])
            return HttpResponseRedirect("/success/url/")
    else:
        form = UploadFileForm()
    return render(request, "upload.html", {"form": form})

Saving Uploaded Files Manually

A common pattern for saving uploaded files is to write them in chunks:


def handle_uploaded_file(f):
    with open("some/file/name.txt", "wb+") as destination:
        for chunk in f.chunks():
            destination.write(chunk)

Using chunks() prevents large files from consuming excessive memory.


Handling Uploaded Files with a Model

If your model contains a FileField, using a ModelForm simplifies file handling. The uploaded file is automatically saved to the directory specified by the field’s upload_to argument.


from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import ModelFormWithFileField

def upload_file(request):
    if request.method == "POST":
        form = ModelFormWithFileField(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect("/success/url/")
    else:
        form = ModelFormWithFileField()
    return render(request, "upload.html", {"form": form})

Assigning Files Manually to a Model

You can also assign uploaded files directly to a model instance:


from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
from .models import ModelWithFileField

def upload_file(request):
    if request.method == "POST":
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            instance = ModelWithFileField(file_field=request.FILES["file"])
            instance.save()
            return HttpResponseRedirect("/success/url/")
    else:
        form = UploadFileForm()
    return render(request, "upload.html", {"form": form})

Assigning Files Outside a Request

You can assign a File-like object manually:


from django.core.management.base import BaseCommand
from django.core.files.base import ContentFile

class MyCommand(BaseCommand):
    def handle(self, *args, **options):
        content_file = ContentFile(b"Hello world!", name="hello-world.txt")
        instance = ModelWithFileField(file_field=content_file)
        instance.save()

Uploading Multiple Files

Django does not yet provide built-in support for multiple file uploads through a single field, but you can implement it by subclassing the field’s widget and field class.


Creating a Multiple File Field

from django import forms

class MultipleFileInput(forms.ClearableFileInput):
    allow_multiple_selected = True

class MultipleFileField(forms.FileField):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault("widget", MultipleFileInput())
        super().__init__(*args, **kwargs)

    def clean(self, data, initial=None):
        single_file_clean = super().clean
        if isinstance(data, (list, tuple)):
            result = [single_file_clean(d, initial) for d in data]
        else:
            result = [single_file_clean(data, initial)]
        return result

class FileFieldForm(forms.Form):
    file_field = MultipleFileField()

Handling Multiple Files in a View

from django.views.generic.edit import FormView
from .forms import FileFieldForm

class FileFieldFormView(FormView):
    form_class = FileFieldForm
    template_name = "upload.html"
    success_url = "..."

    def form_valid(self, form):
        files = form.cleaned_data["file_field"]
        for f in files:
            # Process each file
            pass
        return super().form_valid(form)

Conclusion

Django provides a flexible and powerful system for handling file uploads. Whether you are saving files manually, using models, or implementing multiple file uploads, Django’s tools make it straightforward to manage uploaded content securely and efficiently.


Introduction

In Django, when a user uploads a file, the incoming data is processed by a series of upload handlers. These handlers manage how file data is streamed, stored, and processed before it becomes available in request.FILES. Django’s default behavior uses a combination of in-memory storage and temporary files, but this behavior can be fully customized.


Limitation of Multiple File Uploads at the Model Level

Although you can enable multi-file uploads at the form level using custom widgets and fields, this does not allow storing multiple files in a single FileField on a model. Each FileField can store only one file, regardless of the widget used.


Upload Handlers in Django

Upload handlers are defined in the FILE_UPLOAD_HANDLERS setting. The default configuration is:


[
    "django.core.files.uploadhandler.MemoryFileUploadHandler",
    "django.core.files.uploadhandler.TemporaryFileUploadHandler",
]

  • MemoryFileUploadHandler: Stores small files in memory.
  • TemporaryFileUploadHandler: Streams large files to a temporary file on disk.

You can write custom upload handlers to implement features such as user-level quotas, real-time compression, upload progress bars, or direct streaming to external storage. See Writing custom upload handlers for details.


Where Uploaded Data Is Stored

Before saving uploaded files permanently, Django must store them temporarily:


  • Files smaller than 2.5 MB are stored entirely in memory.
  • Larger files are written to a temporary file in the system’s temp directory (e.g., /tmp on Unix-like systems).

These values are reasonable defaults but can be customized through Django’s file upload settings.


Changing Upload Handler Behavior

Django provides several settings that control upload behavior. Refer to File Upload Settings for configuration options.


Modifying Upload Handlers on the Fly

Some views may require different upload behavior. In such cases, you can modify request.upload_handlers before Django processes the uploaded data. This list initially contains the handlers defined in FILE_UPLOAD_HANDLERS.


Adding a Custom Upload Handler

request.upload_handlers.insert(0, ProgressBarUploadHandler(request))

Using insert(0) ensures the custom handler runs before the default handlers, allowing it to track or modify the upload process from the beginning.


Replacing All Upload Handlers

request.upload_handlers = [ProgressBarUploadHandler(request)]

Important Notes

You must modify upload handlers before accessing request.POST or request.FILES. Once Django begins processing the upload, changing handlers is not allowed and will raise an error.


Because CsrfViewMiddleware accesses request.POST automatically, you must use csrf_exempt on the view where you modify upload handlers. Then, apply csrf_protect to the view that actually processes the request.


Example Using Function-Based Views

from django.views.decorators.csrf import csrf_exempt, csrf_protect

@csrf_exempt
def upload_file_view(request):
    request.upload_handlers.insert(0, ProgressBarUploadHandler(request))
    return _upload_file_view(request)

@csrf_protect
def _upload_file_view(request):
    # Process request
    ...

Example Using Class-Based Views

from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt, csrf_protect

@method_decorator(csrf_exempt, name="dispatch")
class UploadFileView(View):
    def setup(self, request, *args, **kwargs):
        request.upload_handlers.insert(0, ProgressBarUploadHandler(request))
        super().setup(request, *args, **kwargs)

    @method_decorator(csrf_protect)
    def post(self, request, *args, **kwargs):
        # Process request
        ...

Conclusion

Upload handlers are a powerful part of Django’s file upload system. They allow developers to control, customize, or completely replace the upload process. Whether you need progress tracking, size limits, compression, or direct streaming to external services, Django’s upload handler architecture provides the flexibility to implement advanced upload workflows.


Written & researched by Dr. Shahin Siami