~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.,
/tmpon 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