Introduction
Many real Django applications allow users to upload files. A blog may allow image uploads, a school platform may accept PDF assignments, a profile page may allow avatars, and an admin dashboard may manage documents.
Django makes file uploads straightforward, but there are a few important things you must understand:
- how to create file fields in models
- how to configure media files
- how to build upload forms
- how to handle uploaded files in views
- how to display uploaded files in templates
- how to keep uploads organized and safe
In this tutorial, you will learn how to upload images and documents in Django step by step.
What You Will Learn
By the end of this tutorial, you will understand:
- what file uploads are in Django
- the difference between static files and media files
- how to use
FileFieldandImageField - how to configure
MEDIA_URLandMEDIA_ROOT - how to create upload forms
- how to handle file uploads in views
- how to display uploaded files in templates
- common mistakes and best practices
Prerequisites
Before starting, you should already know:
- Django models
- forms
- views and templates
- basic project settings
1. Static Files vs Media Files
Before uploading files, you need to understand the difference between static files and media files.
Static files
These are files that belong to your project itself, such as:
- CSS
- JavaScript
- icons
- fixed images
Media files
These are files uploaded by users, such as:
- profile pictures
- blog images
- PDFs
- documents
In Django:
- static = project assets
- media = user-uploaded content
This tutorial focuses on media files.
2. File Upload Fields in Django
Django provides two main model fields for uploads:
FileField
Used for general files like:
- DOCX
- ZIP
- TXT
ImageField
Used specifically for images like:
- JPG
- PNG
- GIF
- WEBP
ImageField requires the Pillow library.
Install it with:
pip install Pillow3. First Example: Uploading a Document
Let us begin with a simple model for uploaded documents.
models.py
from django.db import models
class Document(models.Model):
title = models.CharField(max_length=200)
file = models.FileField(upload_to='documents/')
uploaded_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.titleExplanation
titlestores the document namefilestores the uploaded fileupload_to='documents/'means files will be stored inside adocuments/folderuploaded_atstores the upload time
4. Example: Uploading an Image
Now let us create an image upload model.
models.py
from django.db import models
class Photo(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(upload_to='photos/')
uploaded_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.titleExplanation
ImageFieldworks likeFileField, but for imagesupload_to='photos/'stores images in aphotos/folder
5. Configure Media Settings
To make file uploads work, you must configure media settings.
settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'What this means
MEDIA_URLis the URL prefix used to access uploaded filesMEDIA_ROOTis the folder where uploaded files are stored on disk
So if a user uploads an image called cat.jpg, Django may store it like this:
media/photos/cat.jpg
and it may be accessible through:
/media/photos/cat.jpg6. Configure URLs for Media Files in Development
During development, Django can serve media files automatically.
Project urls.py
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('your_app.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)Explanation
This tells Django:
- when
DEBUG=True - serve uploaded media files from
MEDIA_ROOT - using the URL prefix
MEDIA_URL
This works in development only. In production, media files are usually served by Nginx, Apache, or cloud storage.
7. Make Migrations
After creating the model, run:
python manage.py makemigrations
python manage.py migrate8. Create a ModelForm for Uploads
Django forms make uploads easier.
forms.py
from django import forms
from .models import Document
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ['title', 'file']For images:
from django import forms
from .models import Photo
class PhotoForm(forms.ModelForm):
class Meta:
model = Photo
fields = ['title', 'image']9. Create the Upload View
Function-Based View Example
views.py
from django.shortcuts import render, redirect
from .forms import DocumentForm
def upload_document(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('document_list')
else:
form = DocumentForm()
return render(request, 'uploads/upload_document.html', {'form': form})Very Important: request.FILES
When handling file uploads, you must include:
request.FILESWithout it, Django will not receive the uploaded file.
10. Create the Upload Template
templates/uploads/upload_document.html
<h1>Upload a Document</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
Very Important: enctype="multipart/form-data"
Without this, the browser will not send the file correctly.
This is one of the most common beginner mistakes.
11. Add the Upload URL
urls.py
from django.urls import path
from .views import upload_document
urlpatterns = [
path('upload/', upload_document, name='upload_document'),
]12. Display Uploaded Files
After uploading, you often want to show uploaded files in a list.
views.py
from django.shortcuts import render
from .models import Document
def document_list(request):
documents = Document.objects.all().order_by('-uploaded_at')
return render(request, 'uploads/document_list.html', {'documents': documents})urls.py
from django.urls import path
from .views import upload_document, document_list
urlpatterns = [
path('upload/', upload_document, name='upload_document'),
path('documents/', document_list, name='document_list'),
]templates/uploads/document_list.html
<h1>Uploaded Documents</h1>
{% for document in documents %}
<p>
{{ document.title }} -
<a href="{{ document.file.url }}">Download</a>
</p>
{% empty %}
<p>No documents uploaded yet.</p>
{% endfor %}
13. Display Uploaded Images
For images, you can display them directly.
views.py
from django.shortcuts import render
from .models import Photo
def photo_list(request):
photos = Photo.objects.all().order_by('-uploaded_at')
return render(request, 'uploads/photo_list.html', {'photos': photos})templates/uploads/photo_list.html
<h1>Photo Gallery</h1>
{% for photo in photos %}
<h3>{{ photo.title }}</h3>
<img src="{{ photo.image.url }}" alt="{{ photo.title }}" width="300">
{% empty %}
<p>No photos uploaded yet.</p>
{% endfor %}14. Full Example: Image Upload App
models.py
from django.db import models
class Photo(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(upload_to='photos/')
uploaded_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.titleforms.py
from django import forms
from .models import Photo
class PhotoForm(forms.ModelForm):
class Meta:
model = Photo
fields = ['title', 'image']views.py
from django.shortcuts import render, redirect
from .forms import PhotoForm
from .models import Photo
def upload_photo(request):
if request.method == 'POST':
form = PhotoForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('photo_list')
else:
form = PhotoForm()
return render(request, 'uploads/upload_photo.html', {'form': form})
def photo_list(request):
photos = Photo.objects.all().order_by('-uploaded_at')
return render(request, 'uploads/photo_list.html', {'photos': photos})urls.py
from django.urls import path
from .views import upload_photo, photo_list
urlpatterns = [
path('photos/upload/', upload_photo, name='upload_photo'),
path('photos/', photo_list, name='photo_list'),
]upload_photo.html
<h1>Upload a Photo</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload Photo</button>
</form>photo_list.html
<h1>All Photos</h1>
{% for photo in photos %}
<h3>{{ photo.title }}</h3>
<img src="{{ photo.image.url }}" alt="{{ photo.title }}" width="250">
{% empty %}
<p>No photos uploaded yet.</p>
{% endfor %}15. Organizing Uploaded Files
The upload_to option can be customized.
Simple folder
image = models.ImageField(upload_to='photos/')Nested folder by year/month
image = models.ImageField(upload_to='photos/%Y/%m/')This helps keep uploads organized.
Example stored path:
media/photos/2026/04/image.jpg16. File Validation Basics
Sometimes you want to limit uploads.
For example:
- only images
- only PDFs
- maximum file size
You can do that with custom form validation.
Example: Only PDF files
forms.py
from django import forms
from .models import Document
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ['title', 'file']
def clean_file(self):
file = self.cleaned_data['file']
if not file.name.endswith('.pdf'):
raise forms.ValidationError('Only PDF files are allowed.')
return file17. File Size Validation Example
from django import forms
from .models import Document
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ['title', 'file']
def clean_file(self):
file = self.cleaned_data['file']
max_size = 5 * 1024 * 1024 # 5 MB
if file.size > max_size:
raise forms.ValidationError('File size must be under 5 MB.')
return file18. Updating Models with Uploaded Files
If you edit an object with a file field, Django allows replacing the file.
Example:
- user edits profile
- uploads a new avatar
- old file reference is replaced in the database
You can handle this using UpdateView or a custom edit view just like any other form, but still remember request.FILES.
19. Deleting Uploaded Files
If you delete a model instance, the database record is deleted, but the file on disk may remain unless you handle cleanup.
For beginners, it is enough to know this behavior exists.
In larger projects, developers often:
- delete the physical file manually
- use signals
- use cleanup packages
20. Using File Uploads in Class-Based Views
You can also use generic views like CreateView.
Example
from django.urls import reverse_lazy
from django.views.generic import CreateView
from .models import Photo
class PhotoCreateView(CreateView):
model = Photo
fields = ['title', 'image']
template_name = 'uploads/upload_photo.html'
success_url = reverse_lazy('photo_list')
Template
<h1>Upload Photo</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
Class-based views make uploads cleaner when building CRUD pages.
21. Common Beginner Mistakes
Forgetting request.FILES
Wrong:
form = DocumentForm(request.POST)Correct:
form = DocumentForm(request.POST, request.FILES)Forgetting enctype="multipart/form-data"
Without it, the file will not be uploaded.
Not configuring MEDIA_URL and MEDIA_ROOT
Without media settings, Django cannot handle uploaded files correctly.
Forgetting Pillow for ImageField
If you use ImageField, install Pillow:
pip install PillowConfusing static and media files
User uploads belong to media, not static.
22. Best Practices
- use
ImageFieldfor images andFileFieldfor general files - validate file type and size
- organize uploads with
upload_to - never trust uploaded files blindly
- use media settings correctly
- test uploads carefully in forms and templates
- keep upload logic simple for beginners
23. Mini Project Example: User Profile Avatar
models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
def __str__(self):
return self.user.usernameTemplate Example
{% if profile.avatar %}
<img src="{{ profile.avatar.url }}" alt="Avatar" width="150">
{% else %}
<p>No avatar uploaded.</p>
{% endif %}This is one of the most common real-world uses of file uploads in Django.
24. Summary
In this tutorial, you learned that:
- Django supports file uploads using
FileFieldandImageField - media files are different from static files
MEDIA_URLandMEDIA_ROOTmust be configured- forms must use
request.FILES - templates must use
enctype="multipart/form-data" - uploaded files can be displayed using
.url - validation is important for safety and quality
File uploads are an essential feature in many real Django projects, and once the basic configuration is correct, they are quite easy to manage.
25. Mini Quiz
1. Which field is used for general file uploads?
A. TextField
B. FileField
C. URLField
D. CharField
2. Which field is used for image uploads?
A. ImageField
B. PhotoField
C. PictureField
D. MediaField
3. What must be included in the form tag for file uploads?
A. method="get"
B. action="upload"
C. enctype="multipart/form-data"
D. target="_blank"
4. What must be passed to the form in the view?
A. request.DATA
B. request.FILES
C. request.MEDIA
D. request.UPLOADS
5. Which library is required for ImageField?
A. NumPy
B. Requests
C. Pillow
D. Pandas
26. What Comes Next?
The next ideal tutorial is:
Tutorial: User Authentication in Django
Subject: login, logout, signup, password management, and authentication basics.
💬 Comments
No comments yet. Be the first to comment!
Login to comment.