Upload files in Django

In this tutorial we will explore how we can upload files in our project using Django.

Basic Walkthrough

Now whenever files are uploaded in the site they end up in request.FILES and for developer it is a must to add attribute enctype="multipart/form-data" in their HTML form, if developer fails to add the attribute then request.FILES will be empty.
Also the form method should be the POST.

Inorder to handle uploaded files Django provides two model fields i.e., FileField and ImageField and files uploaded in FileField and ImageField are stored in the filesystem.

FielField and ImageField are added to database as VARCHAR and contains the reference to the file uploaded.
Incase these two fields are deleted from the database then only reference to the physical file is deleted.
The request.FILES mimics the behavior of dictionary and each key in request.FILES is the name from <input type="file" name="" /> and each value of this dictionary like object is the instance of file uploaded.

In order to add file upload functionality you will have to set MEDIA_URL and MEDIA_ROOT in the settings.py file of the project.

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

For development environment you can use django.contrib.staticfiles.views.serve() view for uploaded files.

from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
............
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

For accessing the MEDIA_URL in the template django.template.context_processors.media must be added context_processeors inside the TEMPLATES config.

Example of file upload

We will look into a sample file upload example.

demo_upload.html

{% extends 'base.html' %}    
{% load static %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="dbfile">
<button type="submit">Upload</button>
</form>
{% if uploaded_file_url %}
<p>File upload location: <a href="{{ demo_file_url }}">{{ demo_file_url }}</a></p>
{% endif %}
<p><a href="{% url 'home' %}">Return to home</a></p>
{% endblock %}
demo_upload.py
from django.shortcuts import render
from django.conf import settings
from django.core.files.storage import FileSystemStorage
def simple_upload(request):
        if request.method == 'POST' and request.FILES['myfile']:
            myfile = request.FILES['dbfile']
            fs = FileSystemStorage()
            filename = fs.save(myfile.name, dbfile)
            uploaded_file_url = fs.url(filename)
            return render(request, 'core/demo_upload.html', {
            'uploaded_file_url': uploaded_file_url
        })
        return render(request, 'core/demo_upload.html')

Upload files using Model Forms

Another convenient way to upload files is using model forms.
Now Model forms come with many features they help to validate, build the absolute url and helps in resolving file name conflicts.

models.py

from django.db import models
class Document(models.Model):
description = models.CharField(max_length=255, blank=True)
document = models.FileField(upload_to='documents/')
uploaded_at = models.DateTimeField(auto_now_add=True)

forms.py

    from django import forms
    from uploads.core.models import Document
    class DocumentForm(forms.ModelForm):
        class Meta:
            model = Document
        fields = ('description', 'document', )

views.py

    def model_form_upload(request):
        if request.method == 'POST':
            form = DocumentForm(request.POST, request.FILES)
            if form.is_valid():
                form.save()
            return redirect('home')
        else:
            form = DocumentForm()
            return render(request, 'core/demo_upload_using_model_form.html', {
        'form': form
    })
demo_upload_using_model_form.html
    {% extends 'base.html' %}
    {% block content %}
      <form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Upload</button>
      </form>
      <p><a href="{% url 'home' %}">Return to home</a></p>
    {% endblock %}

Uploading multiple files

Incase you are fiddling with idea to upload multiple files using one form field then you have to set the multiple HTML attribute of field’s widget:

forms.py

    from django import forms
    class FileFieldForm(forms.Form):
        file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

Next you have to override the post method of your FormView subclass to facilitate multiple file uploads:

views.py

    from django.views.generic.edit import FormView
    from .forms import FileFieldForm
    class FileFieldView(FormView):
        form_class = FileFieldForm
        template_name = 'upload.html'  # Replace with your template.
        success_url = '...'  # Replace with your URL or reverse().
        def post(self, request, *args, **kwargs):
            form_class = self.get_form_class()
            form = self.get_form(form_class)
            files = request.FILES.getlist('file_field')
            if form.is_valid():
                for f in files:
                    ...  # Do something with each file.
                return self.form_valid(form)
            else:
                return self.form_invalid(form)

I hope this piece of work will make your life easy when you integrate file upload option in your code.

AUTHOR

READ NEXT

Boostlog is an online community for developers
who want to share ideas and grow each other.

Delete an article

Deleted articles are gone forever. Are you sure?