Without enctype="multipart/form-data" on your form, uploaded files never reach your Django view. request.FILES will be empty, and you'll have no idea why.
The Default: URL-Encoded Form Data
When a browser submits an HTML form, it encodes the data before sending it. By default, that encoding looks like this:
title=Report&assigned_to=3
Key-value pairs, joined by &, sent as plain text. This works perfectly for text fields, checkboxes, and dropdowns. Simple, readable, efficient.
But files are a different story.
The Problem with Files
Files are binary data — images, PDFs, Word documents. You can't represent a .png or a .pdf as a plain text string in a URL-encoded format. The data would be corrupted or lost entirely.
This is where enctype="multipart/form-data" comes in.
What enctype="multipart/form-data" Actually Does
Adding this attribute tells the browser:
"This form contains a file. Don't encode everything as a single string. Split the data into multiple parts and send each part separately."
Each field — text or file — becomes its own "part" in the HTTP request body, separated by a boundary string. The file's raw binary data is preserved and transmitted intact.
What Happens Without It
Without the attribute, a file upload fails silently:
# In your Django view:
print(request.FILES) # → <MultiValueDict: {}>
The form submits. The view runs. No error is raised. But request.FILES is empty — the file was never included in the request at all.
With it:
print(request.FILES) # → <MultiValueDict: {'file': [<InMemoryUploadedFile: report.pdf>]}>
uploaded_file = request.FILES['file'] # ✅ your view gets the file
The Fix: One Attribute
<!-- ❌ File upload will fail silently -->
<form method="post">
{% csrf_token %}
<input type="file" name="file">
<button type="submit">Upload</button>
</form>
<!-- ✅ File upload works correctly -->
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="file">
<button type="submit">Upload</button>
</form>
Django's Side of the Story
Django's request.FILES is only populated when the incoming request has a Content-Type of multipart/form-data. Without that content type — which the browser sets automatically when enctype is present — Django simply has nowhere to look for file data.
This is also why Django forms with file fields require you to pass request.FILES explicitly:
form = DocumentUploadForm(request.POST, request.FILES)
Not request.POST alone. Both are needed, and both only contain the right data when the form is encoded correctly.
The Rule to Remember
Every form that uploads a file must have enctype="multipart/form-data". No exceptions.
It's easy to forget. It fails silently. And it costs you a frustrating debugging session when you do.