n this article, we will learn how to upload images in a Django application.
Uploading Images in Django
Django has two model fields that allow user uploads FileField
and ImageField
basically ImageField
is a specialized version of FileField
that uses Pillow to confirm that a file is an image.
Let’s, start by creating models.
models.py
from django.db import models
class Image(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(upload_to='images')
def __str__(self):
return self.title
The image column is an ImageField
field that works with the Django’s file storage API, which provides a way to store and retrieve files, as well as read and write them.
The upload_to
parameters specify the location where images will be stored which for this model is MEDIA_ROOT/images/
Setting dynamic paths for the pictures is also possible.
image = models.ImageField(upload_to='users/%Y/%m/%d/', blank=True)
This will store the images in date archives like MEDIA_ROOT/users/2020/04/12
Now, Install Pillow by running the following command in your shell.
pip install Pillow
For Django to serve media files uploaded by users with the development server, add the following settings to the settings.py
file of your project.
settings.py
# Base url to serve media files
MEDIA_URL = '/media/'
# Path where media is stored
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
MEDIA_URL
is the URL that will serve the media files and MEDIA_ROOT
is the path to the root directory where the files are getting stored.
Now add the following configuration in the project’s urls.py
file.
urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
...]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
With that Django’s development server is capable of serving media files. Next, we need to create a model form for the Image model.
forms.py
from django import forms
from .models import Image
class ImageForm(forms.ModelForm):
"""Form for the image model"""
class Meta:
model = Image
fields = ('title', 'image')
This will generate a form with fields title and image, which will be rendered in the templates. So let’s create a barebone template for file uploading.
index.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
{% if img_obj %}
<h3>Succesfully uploaded : {{img_obj.title}}</h3>
<img src="{{ img_obj.image.url}}" alt="connect" style="max-height:300px">
{% endif %}
You must remember to include the enctype
property in the form tag for the uploaded file to be attached to the request properly.
With that let’s write views for handling the form.
views.py
from django.shortcuts import render
from .forms import ImageForm
def image_upload_view(request):
"""Process images uploaded by users"""
if request.method == 'POST':
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
form.save()
# Get the current instance object to display in the template
img_obj = form.instance
return render(request, 'index.html', {'form': form, 'img_obj': img_obj})
else:
form = ImageForm()
return render(request, 'index.html', {'form': form})
This is a very simple view since Django is doing all the work under the hood we are just validating the form and saving it on successful file upload. Now that we are done with the view let’s map it to a URL.
urls.py
urlpatterns = [
......
path('upload/', views.image_upload_view)
......
]
Save all the files and run the server and navigate to the URL you should see the form in action.
#full projects changes :-
#settings.py:-
"""
Django settings for fileupload project.
Generated by 'django-admin startproject' using Django 3.0.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '5j3j^#puur+53r^0o!4ya1=n*y%ka9%$nr^318ikeytg9_a%^5'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'file',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'fileupload.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR , 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'fileupload.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
# Path where media is stored
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
#main urls.py
from django.contrib import admin
from django.urls import path,include
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('file.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
#Go to app folder now:-
#admin.py
from django.contrib import admin
from .models import Image
# Register your models here.
admin.site.register(Image)
# forms.py
from django import forms
from .models import Image
class ImageForm(forms.ModelForm):
"""Form for the image model"""
class Meta:
model = Image
fields = ('title', 'image')
#models.py
from django.db import models
class Image(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(upload_to='images')
def __str__(self):
return self.title
#urls.py
from django.urls import path
from . import views
urlpatterns = [
path('upload/', views.image_upload_view)
]
#views.py
from django.shortcuts import render
from .forms import ImageForm
def image_upload_view(request):
"""Process images uploaded by users"""
if request.method == 'POST':
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
form.save()
# Get the current instance object to display in the template
img_obj = form.instance
return render(request, 'index.html', {'form': form, 'img_obj': img_obj})
else:
form = ImageForm()
return render(request, 'index.html', {'form': form})
#templates/index.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
{% if img_obj %}
<h3>Succesfully uploaded : {{img_obj.title}}</h3>
<img src="{{ img_obj.image.url}}" alt="connect" style="max-height:300px">
{% endif %}