How To Upload Files Using Django?
Django

How To Upload Files Using Django?

Editorial Team
Editorial Team

In this post, we'll learn How to Upload Files Using Django. We'll also discuss about Image uploads. To download the source code of this project, skip to the bottom of this page.

Create a Django Project

Let us start by creating a new Django project to demonstrate file upload.

django-admin startproject djangofileupload

Navigate to the project folder using:

cd djangofileupload

Next, we have to create a new app called book. We'll use this app to save and manage the details of books in our application.

python manage.py startapp book

Register the app under INSTALLED_APPS in settings.py.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'book',
]

Create Book model

Next, create a book model to hold the details of books that we are going to add to our application. It should have the following fields.

  1. id - Primary Key of the table.
  2. name - Name of the Book.
  3. cover_image - An image field to store the cover image of the book. (Image Field).
  4. description - A short description of the book.
  5. download - Field to hold the downloadable file of the book. (File Field).

Here's the content of my models.py file of the book app.

from django.db import models

# Create your models here.
class Book(models.Model):
    id = models.BigAutoField(
        primary_key=True,
    )

    name = models.CharField(
        max_length=150,
        verbose_name='Book Name'
    )

    cover_image = models.ImageField(
        upload_to='cover_images',
        verbose_name='Cover Image'
    )

    description = models.TextField(
        max_length=500,
        verbose_name='Description'
    )

    download = models.FileField(
        upload_to='downloads'
    )

Note that I used ImageField and FileField respectively for cover_image and download fields of the model.

If we use FileField in a model, Django will allow you to upload files of any type to the server.

ImageField is a special type of FileField. The difference between ImageField and FileField is that the ImageField restricts the file type to images.

The upload_to argument provided to the File and Image fields is used to determine where the uploaded images should be saved.

The upload_to parameter is combined with the value of MEDIA_ROOT that the set in the settings.py to determine the physical location of the file uploaded on the server.

Commit changes to the database using:

python manage.py makemigrations
python manage.py migrate

Update settings.py

To set a physical file upload location and url for the uploaded files, add the following two lines to the end of settings.py.

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

The second line instructs Django to upload the files to a folder named uploads in the project directory. You can set this location to a different path or drive.

Create a ModelForm

The easiest way to save data to a model in Django is using Model Forms. Create a fie named forms.py in the book app and add the following code to it.

from django import forms
from django.forms import widgets
from .models import *

class BookForm(forms.ModelForm):
    class Meta:
        model = Book
        fields = '__all__'
        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'description': forms.Textarea(attrs={'class': 'form-control'})
        }

Create the Views

After creating the Model and ModelForm, we can create views to create and list the books.

In views.py of the book app, create the following views.

from django.shortcuts import render, redirect
from .models import *
from .forms import *

# Create your views here.
def home(request):
    context = {}
    context['books'] = Book.objects.all()
    return render(request, 'book/home.html', context)

def create_book(request):
    if request.method == 'GET':
        context = {'form': BookForm()}
        return render(request, 'book/create.html', context)

    elif request.method == 'POST':

        # Passing uploaded files as request.files
        form = BookForm(request.POST, request.FILES)

        # Validating and saving the form
        if form.is_valid():
            form.save()
            return redirect('book_home')
        else:
            context = {'form': form}
            return render(request, 'book/create.html', context)

The home view is used to display the list of books in a table. The file upload is handled in create_book view. In this view, we access the files uploaded by the user using request.FILES and we pass it as a parameter to the model form.

If we are using a model form, Django will take care of the file upload process.

Create templates

Let us create the templates for create and list views.

Create a new folder named templates in the book app and another folder named book in the templates folder.

Create the following filed in the book folder.

base.html - Layout page

<!doctype html>
<html lang="en">
  <head>
    <title>Title</title>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
  </head>
  <body>
      
      {% block content %}
          
      {% endblock content %}
          
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
  </body>
</html>

home.html - Home page to display the list of books

{% extends 'book/base.html' %}

{% block content %}
<div class="container">
    <a href="{% url 'book_create' %}">+ New Book</a>
    <table class="table">
        <tr>
            <th>Image</th>
            <th>Name</th>
            <th>Description</th>
            <th>Action</th>
        </tr>

        {% for book in books %}
        <tr>
            <td>
                <img src="{{ book.cover_image.url }}" alt="Image" class="cover-img">
            </td>
            <td>{{ book.name }}</td>
            <td>{{ book.description }}</td>
            <td>
                <a href="{{ book.download.url }}" download>Download</a>
            </td>
        </tr>
        {% endfor %}

    </table>
</div>
<style>
    .cover-img {
        height: 100px;
    }
</style>
{% endblock content %}

create.html - Page for file upload

{% extends 'book/base.html' %}

{% block content %}
<div class="container-fluid">
    <div class="row">
        <div class="col-sm-6 offset-sm-3">
            <h1>Create Book</h1>
            <form method="post" enctype="multipart/form-data">
                {{ form.as_p }}
                <div class="form-group d-flex">
                    {% csrf_token %}
                    <button class="btn btn-primary ml-auto">Save</button>
                </div>
            </form>
        </div>
    </div>
</div>
{% endblock content %}

Update routes

Create a new file named urls.py in the book app and add the following content.

book/urls.py

from django.urls import path
from .views import *

urlpatterns = [
    path('', home, name='book_home'),
    path('create/', create_book, name='book_create'),
]

Update the main urls.py file the project folder. This is an important step. Without updating this file, we will not be able to view or access the uploaded files.

djangofileupload/urls.py

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('admin/', admin.site.urls),
    path('', include('book.urls')),
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Uploading Files

We are now ready to upload files using Django. Navigate to the project directory and run the project using python manage.py runserver. Click on the new book link and fill the form.

Choose a cover image (Only image files can be selected) and a file (any file format) and hit the save button. The files will be uploaded and saved on the server.

The uploaded files are not saved in the database. Instead, the files are stored in the hard drive in the location specified in settings.py and the location is saved in the database.

When a conflict in the file name occurs, Django will automatically generate a unique file name for the newly uploaded file. This ensures that the old files are not overwritten.


Download the source code

The source code of the project can be download from GitHub. Refer the ReadMe file of the project for more instructions.

geekinsta/DjangoFIleUpload
Simple application to demonstrate file upload using Django - geekinsta/DjangoFIleUpload

If you have any questions, let me know in the comments bellow.