DEV Community

Cover image for How to handle media uploads in Django
Edun Rilwan
Edun Rilwan

Posted on • Edited on

How to handle media uploads in Django

It is a common feature in most web apps to prompt users to upload files or documents. These files include image files (.jpeg, .jpg, .png) or other document files like PDFs, audio files (.mp3), etc.

Django, a very popular and powerful web framework in Python provides built-in methods and utilities that enables seamless upload and storage of files in web applications.

In Django, there are 3 ways to accept media uploads from users. They include the following:

  • Django ModelForms

  • Django Forms

  • Pure HTML forms

In this tutorial, you will learn how to handle media uploads with Django ModelForms using a local storage. Django's ModelForm provides a convenient and faster way to create forms in Django. They are also very customizable.

By the end of this tutorial, you would have learned the following:

  • How to receive media files via a ModelForm
  • How to handle and save the received file object
  • How to display saved image files on a web page
  • How to make saved files available for download by users.

Project requirements

  • Python: You need a Python interpreter installed on your computer. Preferably python>=3.8

  • Django: The latest version of Django is required.

Create a new virtual environment using the virtualenv package in Python:

virtualenv env
Enter fullscreen mode Exit fullscreen mode

Use the command below to activate the virtual environment:

Windows:

env\Scripts\activate
Enter fullscreen mode Exit fullscreen mode

Linux/macOS:

env/bin/activate
Enter fullscreen mode Exit fullscreen mode

Install Django in the new virtual environment:

pip install Django
Enter fullscreen mode Exit fullscreen mode

Note: To confirm your virtual environment (VE) is activated, check to see the name of your VE in a bracket like the one below:

(env) >>>
Enter fullscreen mode Exit fullscreen mode

Getting started with Django file upload

You need to create a new Django project and app to learn how Django handles media uploads.

Create a Django project

Follow the steps below to create a Django project:

a. Open your terminal(check that your VE is activated).
b. Run the command below to create a Django project

django-admin startproject my_project
Enter fullscreen mode Exit fullscreen mode

c. Enter the command below to move into the new my_project folder

cd my_project
Enter fullscreen mode Exit fullscreen mode

Next step is to create an app.

Create a Django app

Run the command below in the terminal to create an app named file_upload

python manage.py startapp file_upload

Enter fullscreen mode Exit fullscreen mode

Open the settings.py file in your project folder and add the app to the INSTALLED_APPS list as seen below:

#my_project/settings.py

INSTALLED_APPS = [
...
"file_upload"
]
Enter fullscreen mode Exit fullscreen mode

Django MEDIA ROOT and MEDIA URL

MEDIA_ROOT and MEDIA_URL variables are crucial in handling media uploads in a local filesystem storage. They provide a way of accessing and storing saved files in a Django app.

Django MEDIA ROOT

MEDIA ROOT refers to the root folder where all uploaded files are stored in a Django web app. It refers to the folder where all files can be accessed from.

How to set up a MEDIA ROOT

To set up a MEDIA ROOT, do the following:

a. Create a new folder named uploads in your project folder


#file_arrangement
my_project
   \__ my_project
   \__ file_upload
   \__ uploads
Enter fullscreen mode Exit fullscreen mode

b. Open settings.py file and include the following line of code in it:

MEDIA_ROOT = BASE_DIR / "uploads"
Enter fullscreen mode Exit fullscreen mode

This setting instructs Django to save uploaded files to the uploads folder within your project, that is BASE_DIR.

BASE_DIR is a variable automatically set by Django. It contains the file path to your current project, which is also known as the base directory.

Django MEDIA URL

MEDIA URL refers to the root URL that renders user-uploaded files present in the MEDIA ROOT of a web app.

For example, if you uploaded an image file titled example.jpg, it is rendered on the web via a url like the one below:

https://mysite/[MEDIA_URL]/[MEDIA_ROOT]/images/example.jpg

The URL above is analyzed as follows:

  • mysite is the domain name of your website.
  • media_url is the base/root url for uploaded media.
  • media_root is the root folder for uploaded media.
  • images is another folder inside the MEDIA ROOT that stores image files only
  • example.jpg is the file name.

How to set up a MEDIA URL

a. Open your project's settings.py file and add the code below:

MEDIA_URL = "files/"
Enter fullscreen mode Exit fullscreen mode

b. Open the urls.py file in your project folder
c. Add the following import statements:

from django.conf import settings
from django.conf.urls.static import static
Enter fullscreen mode Exit fullscreen mode

d. Write the following code below the urlpatterns list in the urls.py file:

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Enter fullscreen mode Exit fullscreen mode

In the steps above, a MEDIA URL, named files is created. This root url for media uploads is finally added to the list of URLs.

Create a Database Model

The next step is to create a database model named Uploads. This model will have three field types which includes: A Charfield, FileField and an ImageField. Follow the steps below to create the Uploads model:

a. Go to the models.py file in your app
b. Create a simple database model titled Uploads

from django.db import models

# Create your models here.
class Uploads(models.Model):
   caption = models.CharField(unique=False, null=False, blank=False, max_length=20, default="An image")
   file_field = models.FileField(upload_to="files", null=False, blank=False)
   image_field = models.ImageField(upload_to="images", null=False, blank=False)
Enter fullscreen mode Exit fullscreen mode

The functions of each field are listed below:

CharField stores textual data.
FileField stores files such as PDFs, docx, etc.
ImagField stores image files.

The FileField and ImageField have an upload_to argument. This refers to a new folder inside your project's MEDIA ROOT where the content of each file field will be stored. It is created automatically when a file is uploaded to each field.

Run migrations for the database

Run database migrations via the steps below:

a. Open the terminal and run this command

python manage.py makemigrations

Enter fullscreen mode Exit fullscreen mode

b. Run the command below to add the migrations to a file

python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

Migrations help to track changes made to the database.

Build a ModelForm

Follow the steps below to build a ModelForm:

a. Create a forms.py file in your app folder

my_project
   \___ file_upload
          \___ ...
          \___ forms.py
Enter fullscreen mode Exit fullscreen mode

b. Add the code below to the file:

from django import forms
from .models import Uploads

class FileUploadForm(forms.ModelForm):
   class Meta:
       model = Uploads
       fields = "__all__"
Enter fullscreen mode Exit fullscreen mode

The code above creates a ModelFormbased on the structure of the Uploads model. The __all__ method means that the form should contain all the fields in the database model.

Create a view for media uploads

Follow the steps below to create a view function:

a. Open the views.py file
b. Add the code below

from django.shortcuts import render, redirect
from .forms import FileUploadForm
from .models import Uploads


# Create your views here.

def handle_upload(request):
   form = FileUploadForm()
   if request.method == "POST":
       form = FileUploadForm(request.POST, request.FILES)
       if form.is_valid():
           form.save()

   return render(request, "form.html", context={"form": form})
Enter fullscreen mode Exit fullscreen mode

The view function renders the ModelForm through a form.html file that will be created in the next step.

This view also accepts POST requests from the ModelForm when the user submits their uploads. It verifies that there are no form errors before saving the user input.

It is necessary to include the request.FILES and request.POSTdictionary in the form class for each POST request.

POST requests are usually sent with a requests.POST dictionary. When files are involved, a request.FILES dictionary is added.

Uploaded files are stored temporarily in a request.FILES dictionary. Each key in this dictionary holds the data of a particular file field in the form submitted.

For example, if you created a form with a FileField named "images", you can access the file data in your views function via the code below:

request.FILES['images']
Enter fullscreen mode Exit fullscreen mode

Create the homepage file

You need to create an HTML file named form.html that'll render the form. Follow the steps below to do create a web page:

a. Create a new folder named templates in your project

my_project
   \___ my_project
   \___ ...
   \___ templates
   \___ ...

Enter fullscreen mode Exit fullscreen mode

b. Create a new HTML file named form.html inside this folder
c. Add the code below inside this file

<head>
   <meta charset="UTF-8">
   <title>Forms practise</title>
</head>


<body>

<form method="post" action="" enctype="multipart/form-data">
   {% csrf_token %}

   {{ form.as_p }}
   <input type="submit" name="submit">

</form>

</body> 
Enter fullscreen mode Exit fullscreen mode

The HTML code above displays the form to the user through form.as_p, while the {% csrf_token %} enables secured transfer of form data

The enctype="multipart/form-data" variable enables the form to send file data.

Finally, you need to register the templates folder with Django so it can access it.

To do this, open the settings.py file in your project folder and add the code below to the TEMPLATESlist in this file:

TEMPLATES = [
    {
        '...',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        '...'
    }
]
Enter fullscreen mode Exit fullscreen mode

Configure app urls.

The next step is to bind the view function to a url. Follow the steps below to do this:

a. Open the urls.py file in your app folder

my_project
   \___ file_upload
      \___ ...
      \___ urls.py
      \___ ...
Enter fullscreen mode Exit fullscreen mode

b. Add the code below to this file

from django.urls import path
from file_upload import views

urlpatterns = [path("", views.handle_upload, name="home")]
Enter fullscreen mode Exit fullscreen mode

c. Open the urls.py file in your project folder

my_project
  \___ my_project
     \___ ...
     \___ urls.py
     \___ ...

Enter fullscreen mode Exit fullscreen mode

d. Register your app URLs to the urlpatterns list in your project.

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    "...",
    path("", include("file_upload.urls")),
]
Enter fullscreen mode Exit fullscreen mode

Test the app

a. Run the command below in your terminal

python manage.py runserver
Enter fullscreen mode Exit fullscreen mode

b. Click on the link to open the web page
c. Click on the _Choose file _button to upload your files.

Web page showing how to upload files in Django

c. Enter a caption of your choice.
d. Submit the form.
e. Proceed to the uploadfolder, you would see two new folders named filesand images.

In the files folder, you would see the document you uploaded.
In the images folder, you would see the image file you uploaded.

Display user uploads

In most cases, users would need access to their files. You can display media uploads to users using a simple .url attribute. The steps below show you how to display uploaded files to users:

a. Open the views.py file
b. Update the view function to contain the Uploads model and pass it to the render function.

from django.shortcuts import render, redirect
from .forms import FileUploadForm
from .models import Uploads

# Create your views here.
def handle_upload(request):
   form = FileUploadForm()
   uploads = Uploads.objects.all()
   if request.method == "POST":
       form = FileUploadForm(request.POST, request.FILES)
       if form.is_valid():
           form.save()
           return redirect("home")

   return render(request, "form.html", context={"form": form, "uploads": uploads})
Enter fullscreen mode Exit fullscreen mode

c. Proceed to the form.html file
d. Add this code below the form in the HTML file

{% for media in uploads %}
{% if media %}

<div style="margin: 20px 0px;">

   <img src="{{ media.image_field.url }}" height="200px;" width="200px;">
   <p>{{ media.caption }}</p>
   <p>Download your file <a href="{{ media.file_field.url }}">here</a></p>

</div>

{% endif %}
{% endfor %}
Enter fullscreen mode Exit fullscreen mode

e. Wait for the server to reload
f. Open the browser and refresh the web page

This process simply queries all records in the Uploads model, adds it to the context dictionary so it can be accessed and used in the HTML file.

The image you uploaded will be displayed on the web page and your document will be available for download. Here is an example below:

An image displaying user uploads in Django

Conclusion

Leveraging Django's ModelForms for file uploads simplifies the process of handling user-submitted files. Whether it's for pictures, documents or any other type of file, ModelForms provides an efficient and structured way to manage file uploads in Django.

Frequently asked questions (FAQs)

What type of media files can be uploaded in Django?

You can upload files of different sizes and formats in Django. However, if you are using a local file-storage, you will get to a point where the memory gets full and you will need to use a cloud service like AWS, Google clouds, etc.

An overloaded memory will affect site performance.

How can I secure media uploads in Django?

There are different security measures you can apply to media uploads in Django. They include:

  1. Verifying the file formats before saving them. That is, by checking the file extensions, such as .png, .jpg, .pdf, etc. to be sure they are safe
  2. Sometimes, reading file metadata before saving is also important. However, you may need to use third-party Python libraries to like Pillow to implement this.

How to handle media uploads in a production environment?

It is not advisable to use a local file storage in a production environment. This is because such implementation may have security implications on stored files.

Using cloud services enhance application performance and provide more flexibility and security to uploaded files.

Can I resize or manipulate uploaded images in Django?

Yes, you can.

Before saving an uploaded file, you can get the file object from the request.FILES dictionary and use it directly with a file manipulation library like Pillow, OpenCV, etc. in Python.

After editing the image, you can then save it to a file of your choice.

How does the Django Filesystem work?

When a user uploads a file in Django, the Django filesystem has two handlers that handles file uploads. For small files, they are saved to memory using the (handler) handler while the (handler) handler handles large files by saving them to a temporary file.

What happens when I delete saved files in Django?

Deleted files are immediately removed from the MEDIA ROOT of your app. Therefore, trying to access a deleted file through the .url attribute will throw an error.

Top comments (0)