Single or Multiple Files Upload Example in Django Framework

In your application or project there is always a requirement for uploading a file data. This file data could be in a specific format depending on your requirement. Here I am going to explain you how you can upload single or multiple files in your python based Django framework. I am assuming you have a basic knowledge on Python and Django framework before you proceed further. I am also going to show you how to implement CSRF token for uploading files.

In Django framework the file data is placed into request.FILES. You need a FileField form that a view will handle this form and this form will receive file data in request.FILES which is a dictionary containing a key for each FileField. So let’s say if your form has an input field with name file and form has an attribute enctype="multipart/form-data", then file data can be accessible as request.FILES['file']. If your form does not have attribute enctype="multipart/form-data" then request.FILES['file'] will be empty.

Let’s get into the coding part.

Prerequisites

Python 3.9.0, Django 3.1.2

Project Setup

The first thing you need to create project directory. The project name is djangofilesupload which you will create using the following command.

django-admin startproject djangofilesupload

Next step is to create an app inside the above project directory to perform files upload operations. Create an app called filesupload using the following command. Make sure you execute the following command from the project’s root directory djangofilesupload, because you are going to create the following app directory under the project’s root directory.

django-admin startapp filesupload

The required project and app structures will be created.

Now you need to add this filesupload app into the project settings. So edit the file djangofilesupload/djangofilesupload/settings.py and add the following line into INSTALLED_APPS section at the end:

INSTALLED_APPS = [
    ...
    'filesupload.apps.FilesuploadConfig',
]

The above line is formed using the file djangofilesupload/filesupload/apps.py. You will see the FilesuploadConfig class in this file with the name = ‘filesupload’.

Template or View File

The template or view file is nothing but you write code on HTML file what you want to display on UI (User Interface). For this file upload functionality I am going to put only one field that is file which will be used for browsing and selecting file or files.

<!DOCTYPE html>
<html>
    <head>
        <title>Django - Single File Upload</title>
    </head>
    <body>
		<div style="width: 500px; margin: auto;">
			<fieldset name="Single File Upload">
				{% if msg %} {% autoescape off %} {{ msg }} {% endautoescape %} {% endif %}
				<form method="post" action="/" enctype="multipart/form-data">
					{% csrf_token %}
					<dl>
						<p>
							<label>Browse and select a file</label>&nbsp;&nbsp;
							<input type="file" name="file" autocomplete="off" required>
						</p>
					</dl>
					<p>
						<input type="submit" value="Upload">
					</p>
				</form>
			</fieldset>
		</div>
    </body>
</html>

The name of the above template file is single.html and put it under filesupload/templates directory.

In the above template file I am showing message if there is any from the server once file is uploaded. I have also turned autoescape off if there is any HTML tag coming from server side. Otherwise your HTML tags, for example, having < or > will be converted into &lt; and &gt; respectively. This is correct output in the HTML page but your corresponding DOM object will not be created.

Let’s say if your server is sending response as shown below:

<span style="color: green;">File successfully uploaded</span>

And if you do not turn auto escape off then you will see the following result once your file successfully uploaded to the server location.

single or multiple files upload example in django

The another important thing is you need to set CSRF token on the form using {% csrf_token %} otherwise you won’t be able to upload file and you would get the following errors:

CSRF token is not set

CSRF Token missing or incorrect

You also need to ensure to check the CSRF token on your server side code and you will later when you go through the code in views.py file.

Form

The Django Form will map the fields to form on your template file. In the above template or view file I have kept only one field called file which is used to select a file. A view handling this form will receive data into request.FILES.

request.FILES will only contain data if the HTTP request method is POST, at least one file is posted and the corresponding form has an attribute enctype="multipart/form-data", because dealing with forms that have FileField and ImageField fields are more complex.

The following code snippets are written into form.py file under directory filesupload.

from django import forms

class UploadFileForm(forms.Form):
    file = forms.FileField()

By default files will be uploaded into project’s root directory. If you want to change the destination for upload then you can pass as shown below:

file = forms.FileField(upload_to='your directory name/')

Views

In this view I am going to show how to upload file into a server location. You will also see how file data is passed from request to Form. Here also notice how I have used CSRF decorator to ensure the CSRF token.

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES['file'])
            context = {'msg' : '<span style="color: green;">File successfully uploaded</span>'}
            return render(request, "single.html", context)
    else:
        form = UploadFileForm()
    return render(request, 'single.html', {'form': form})

def handle_uploaded_file(f):
    with open(f.name, 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)

Note that you have to pass request.FILES into the Form‘s constructor to bind the file data into a Form.

Looping over UploadedFile.chunks() instead of using read() ensures that large files don’t overwhelm your system’s memory.

Ideally the function handle_uploaded_file() should be put into common utility file, but just for the sake of this example I have kept into the same file filesupload/views.py.

Before you save the file onto disk the uploaded file data is stored under the tmp folder and the file name is generated something like tmpzfp414.upload. If the file size is up to 2.5 MB then file is not saved under the tmp folder and entire content is read from the memory and the reading becomes very fast.

URLs

Now you need to define the path or URL which will call the appropriate function (for this example, upload_file()) on your views.py file. You need to create a file urls.py under filesupload folder with the following code snippets.

from django.urls import path
from django.conf import settings

from . import views

urlpatterns = [
    path('', views.upload_file, name='upload_file'),
]

The path() function is passed four arguments, two required: route and view, and two optional: kwargs, and name.

route is a string that contains a URL pattern.

view calls the specified view function with an HttpRequest object as the first argument and any “captured” values from the route as keyword arguments.

kwargs are arbitrary keyword arguments can be passed in a dictionary to the target view.

name – naming your URL lets you refer to it unambiguously from elsewhere in Django, especially from within templates.

Another important thing you need to do is to configure the URL into the project. This (filesupload) is an app and your project does not know anything about this URL. So add the following line into djangofilesupload/djangofilesupload/urls.py file under urlpatterns = [...].

path('', include('filesupload.urls')),

Deploying Application

Now I am ready to test the app I have built. Let’s fire up the server from the command line using manage.py runserver. The application will run on default port 8000. If you want to change the default host/port of the server then you can read tutorial How to change default host/port in Django.

Testing the Application

When you hit URL http://localhost:8000 on browser, your home page looks similar to the following image:

single or multiple files upload example in django

Once you select and click on Upload button you will see the success message as shown below:

single or multiple files upload example in django

The file gets uploaded into the project’s root directory djangofilesupload.

Multiple Files Upload

The above example has shown you how to upload single file using the browse button. Here I am going to explain you how to upload multiple files using the single browse button.

Here I am going to create a separate template or view file (filesupload/templates/multiple.html) for user interface (UI).

<!DOCTYPE html>
<html>
    <head>
        <title>Django - Multiple Files Upload</title>
    </head>
    <body>
		<div style="width: 500px; margin: auto;">
			<fieldset name="Multiple Files Upload">
				{% if msg %} {% autoescape off %} {{ msg }} {% endautoescape %} {% endif %}
				<form method="post" action="/multiple" enctype="multipart/form-data">
					{% csrf_token %}
					<dl>
						<p>
							<label>Browse and select one or more files</label>&nbsp;&nbsp;
							<input type="file" name="files" autocomplete="off" required multiple>
						</p>
					</dl>
					<p>
						<input type="submit" value="Upload">
					</p>
				</form>
			</fieldset>
		</div>
    </body>
</html>

You need to add another entry to the forms.py file as shown below for multiple files. So the file field is used to upload single file and files field is used to upload multiple files.

from django import forms

class UploadFileForm(forms.Form):
    file = forms.FileField()
    files = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

You need to modify the views.py and add the following function into it.

@ensure_csrf_cookie
def upload_multiple_files(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        files = request.FILES.getlist('files')
        if form.is_valid():
            for f in files:
                handle_uploaded_file(f)
            context = {'msg' : '<span style="color: green;">File successfully uploaded</span>'}
            return render(request, "multiple.html", context)
    else:
        form = UploadFileForm()
    return render(request, 'multiple.html', {'form': form})

You need to update the file filesupload/urls.py to add another path for uploading multiple files.

path('multiple', views.upload_multiple_files, name='upload_multiple_files'),

So you’re done with coding. Let’s test it. Hitting the URL http://localhost:8000/multiple in the browser will display the following page:

single or multiple files upload example in django

Now select one or more files to upload. Once successfully uploaded you will see the following page.

single or multiple files upload example in django

Hope you got idea how to upload single and multiple files using Django framework. You may also read of other ways of uploading files into server.

Source Code

Download

Leave a Comment