How to upload Files using Django jQuery and AJAX

Introduction

Here I am going to show you how to use AJAX in Django framework and how to upload files using Django jQuery and AJAX. This example can be used to upload both single and multiple files to the server. Only thing is you need to select single file if you want to upload only single file. For multiple files upload you need to hold CTRL key (on Windows OS) on keyboard and select multiple files for upload. The uploaded files are stored into the root directory of the project.

upload files using django jquery and ajax

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.

Related Posts:

In this example as I am using AJAX to upload files, so I won’t use <form/> tag on the view page. Instead of this I need to make sure that I am sending data from UI to Server in an appropriate manner.

Prerequisites

Python 3.9.5, Django 3.2.4

Project Setup

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

django-admin startproject djangoajaxfilesupload

Next step is to create an app inside the above project directory to where actually you will create projects files for upload operations. Create an app called ajaxfilesupload using the following command. Make sure you execute the following command from the project’s root directory djangoajaxfilesupload, because you are going to create the following app directory under the project’s root directory.

django-admin startapp ajaxfilesupload

The required project and app structures will be created.

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

INSTALLED_APPS = [
    ...
    ''ajaxfilesupload.apps.AjaxfilesuploadConfig',',
]

The above line is formed using the file djangoajaxfilesupload/ajaxfilesupload/apps.py. You will see the AjaxfilesuploadConfig class in this file with the name = ‘ajaxfilesupload’.

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.

The name of the template file is files_upload.html and put it under ajaxfilesupload/templates directory.

<!DOCTYPE html>
<html>
    <head>
        <title>Django AJAX Files Upload</title>
    </head>
    <body>
		<div style="width: 500px; margin: auto;">
			<fieldset name="Multiple Files Upload">
				{% if msg %} {% autoescape off %} {{ msg }} {% endautoescape %} {% endif %}
				<div id="msg"></div>
				<p>
					{% csrf_token %}
					<input type="file" id="multiFiles" name="files[]" multiple="multiple"/>
					<button id="upload">Upload</button>
				</p>
			</fieldset>
		</div>
		
		<script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
		
		<script type="text/javascript">
			$(document).ready(function (e) {
				$('#upload').on('click', function () {
					var form_data = new FormData();
					var ins = document.getElementById('multiFiles').files.length;
					
					if(ins == 0) {
						$('#msg').html('<span style="color:red">Select at least one file</span>');
						return;
					}
					
					for (var x = 0; x < ins; x++) {
						form_data.append("files[]", document.getElementById('multiFiles').files[x]);
					}
					
					csrf_token = $('input[name="csrfmiddlewaretoken"]').val();
					
					//console.log(csrf_token);
					
					form_data.append("csrfmiddlewaretoken", csrf_token);
					
					$.ajax({
						url: 'upload', // point to server-side URL
						dataType: 'json', // what to expect back from server
						cache: false,
						contentType: false,
						processData: false,
						//data: {'data': form_data, 'csrfmiddlewaretoken': csrf_token},
						data: form_data,
						type: 'post',
						success: function (response) { // display success response
							$('#msg').html(response.msg);
						},
						error: function (response) {
							$('#msg').html(response.message); // display error response
						}
					});
				});
			});
		</script>
    </body>
</html>

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.

upload files using django jquery and ajax

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.

In the above code notice how I am setting csrf token through AJAX call in jQuery. I am first retrieving the csrf token from the hidden input field:

csrf_token = $('input[name="csrfmiddlewaretoken"]').val();

Then I am setting to the form data:

var form_data = new FormData();
...
form_data.append("csrfmiddlewaretoken", csrf_token);

the csrfmiddlewaretoken is the key where you need to set the csrf token through AJAX call.

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 server. Here also notice how I have used CSRF decorator to ensure the CSRF token.

from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def upload_files(request):
    if request.method == "GET":
        return render(request, 'files_upload.html', )
    if request.method == 'POST':
        files = request.FILES.getlist('files[]', None)
        #print(files)
        for f in files:
            handle_uploaded_file(f)
        return JsonResponse({'msg':'<span style="color: green;">File successfully uploaded</span>'})
    else:
        return render(request, 'files_upload.html', )

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

In the above code, the http GET method is used to display only the view file or user interface to the end users.

The files[] parameter where each file gets appended to the FormData in AJAX call is used to retrieve all files in server side. Then iterating each file from a list of files gets saved to the server location. Note, here the uploaded files will be saved to the root directory of the project. You can also specify the destination for the file to be stored.

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 ajaxfilesupload/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_files()) on your views.py file. You need to create a file urls.py under ajaxfilesupload folder with the following code snippets.

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

from . import views

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

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 djangoajaxfilesupload/djangoajaxfilesupload/urls.py file under urlpatterns = [...].

path('', include('ajaxfilesupload.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:

upload files using django jquery and ajax technique

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

upload files using django jquery and ajax technique

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

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *