File & Image Uploads
A file upload is the process of accepting a file from a visitor's browser, writing its bytes to disk under your media folder, and saving the resulting path in the database.
Learn File & Image Uploads in our free Django course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Django course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll add a FileField or ImageField to a model, configure MEDIA_ROOT and MEDIA_URL , read the upload from request.FILES , control where files land with upload_to , and serve the media back during development.
A FileField stores a path in the database and writes the bytes to disk. An ImageField does the same but also confirms the upload is a real image. Both need two settings: MEDIA_ROOT (where files are written) and MEDIA_URL (the URL prefix they're served under).
Files don't arrive in request.POST — they come in request.FILES . To handle them you bind your form to both , and the HTML form must declare enctype="multipart/form-data" . Once form.is_valid() passes, form.save() writes the bytes and the row together.
upload_to can be a fixed string folder or a function that returns a path per file. A function lets you bucket uploads by user and date, which keeps directories small and avoids name collisions. Django calls it with the model instance and the original filename.
In development you must wire up media serving yourself. Add a static() mapping in the project urls.py , guarded by DEBUG .
Django serves an uploaded file at MEDIA_URL joined with its relative path. Fill in the blank with the standard media URL prefix.
❌ The file never arrives (request.FILES is empty)
The form tag is missing enctype , or you bound only request.POST .
✅ Fix: add enctype="multipart/form-data" and build Form(request.POST, request.FILES) .
❌ Cannot use ImageField because Pillow is not installed
ImageField validates images using the Pillow library, which isn't bundled with Django.
✅ Fix: install it with pip install Pillow , then run your migrations.
The dev server doesn't serve MEDIA_URL unless you tell it to.
✅ Fix: append static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) in urls.py under if settings.DEBUG .
Write a validator that rejects files that are too big or have a disallowed extension, then returns the path the file would be saved to — exactly the kind of check you'd add in a form's clean_avatar() .
Lesson complete — your app accepts uploads!
You can add a FileField or ImageField , set MEDIA_ROOT and MEDIA_URL , bind a form to request.POST and request.FILES , route files with upload_to , and serve media in development.
🚀 Up next: Sending Email — deliver messages with send_mail and templated HTML emails.
Practice quiz
Which model field stores an uploaded document like a PDF?
- TextField
- FileField
- CharField
- BinaryField
Answer: FileField. FileField stores the file on disk and saves its path in the database.
What does ImageField add over FileField?
- Automatic thumbnails
- Image validation plus width and height attributes
- Cloud storage
- Compression
Answer: Image validation plus width and height attributes. ImageField validates the upload is a real image and exposes width and height; it needs Pillow.
Which library must be installed to use ImageField?
- NumPy
- requests
- Pillow
- OpenCV
Answer: Pillow. ImageField requires the Pillow imaging library.
What does MEDIA_ROOT define?
- The public URL prefix for media
- A database table name
- The CDN domain
- The filesystem path where uploaded files are written
Answer: The filesystem path where uploaded files are written. MEDIA_ROOT is the absolute filesystem path where Django stores uploaded files.
What does MEDIA_URL define?
- The public URL prefix uploaded files are served under
- The disk path for uploads
- The database name
- The static files directory
Answer: The public URL prefix uploaded files are served under. MEDIA_URL is the public URL prefix, e.g. /media/, used to build a file's .url.
What enctype must an HTML form have to upload files?
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- application/json
Answer: multipart/form-data. Without enctype="multipart/form-data" the file never reaches request.FILES.
How must you construct a form to bind uploaded files?
- MyForm(request.FILES)
- MyForm(request.GET)
- MyForm(request.POST, request.FILES)
- MyForm(request.POST)
Answer: MyForm(request.POST, request.FILES). Pass both request.POST and request.FILES so file fields are bound.
Where does Django put uploaded files arriving in a request?
- request.POST
- request.GET
- request.body
- request.FILES
Answer: request.FILES. Uploaded files are available in request.FILES.
How do you get a file field's public URL in a template?
- obj.file.url
- obj.file.path_url
- obj.file.link
- obj.file.href
Answer: obj.file.url. The file field's .url attribute combines MEDIA_URL with the stored relative path.
How do you serve uploaded media in development with DEBUG=True?
- Use collectstatic
- Add a static() mapping of MEDIA_URL to MEDIA_ROOT in urls.py
- Set DEBUG=False
- Nothing — it works automatically in production mode
Answer: Add a static() mapping of MEDIA_URL to MEDIA_ROOT in urls.py. In development add static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) to urls.py.