Upload image into custom folder in Django

Today we are going to upload image using django model. We’re going to create a small project where we can implement Django’s file upload, save and view functions, with a database but where the images will be stored on a hard drive. We assuming that you already configured your project. If you want to know configure django project see our blog Setup Your First Django Project .

So, this is our project structure

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py
   firstapp/
      __init__.py
      admin.py
      apps.py
      migrations/
          __init__.py
      models.py
      tests.py
      views.py

Configure media folder

To store files/images need to create media folder in our root directory. configure your media folder add these line into your setting.py file.


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

Creating the Model

Let’s start off by defining a model of a Profile, which directly matches to a database table. A form can then be created to represent a blank slate of this model, allowing the user to fill in the details. In the firstapp/models.py file, we can define a model that extends the models.Model class, which then inherits the functionality to be saved in the database:


from django.db import models
def user_directory_path(instance, filename):
    # file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
    return 'user_{0}/{1}'.format(instance.name, filename)
    

# Create your models here.

class Profile(models.Model): 
    name            = models.CharField(max_length=100)  
    email           = models.CharField(max_length=100,null=True,default="")   
    profile_picture = models.ImageField(upload_to=user_directory_path, blank=True, null=True)
    created_at      = models.DateTimeField(auto_now_add=True)
  

Here, profile_picture field’s datatype is ImageField which store a file path and set path to uploading image is in upload_to attribute.

Here upload_to attribute contain a custom function user_directory_path which is responsible to create custom folder by name into media folder and upload image.

Now register our model into firstapp/admin.py:

from django.contrib import admin

# Register your models here.
from .models import Profile

admin.site.register(Profile)

Now run command to migrate your model:

python manage.py makemigrations

Here you may get an error : ImageField because Pillow is not installed

To solve this error we need to run this command:

python -m pip install Pillow

Now, again run these 2 commands to migrate :

python manage.py makemigrations
python manage.py migrate

Create superuser for database

Now, create super user to login you database:

 python manage.py createsuperuser

Enter your username and password to create superuser.

Registering URL Paths

let’s configure the URL paths that will allow a user to use this application. To do this, let’s create a urls.py file inside our app. Then we can go on and “include” its content in the project-level urls.py file.

Our mysite/urls.py will look something like this:

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include("firstapp.urls")),
]

Our firstapp/urls.py will look something like this:


from django.urls import path
from firstapp import views
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('', views.index,name="index"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

The static() function maps the MEDIA_URL, to the actual path to where our files reside, MEDIA_ROOT. Requests that try to reach any of our files can get access via this MEDIA_URL, which is automatically prefixed to the [url] attribute of  ImageField instances.

Creating a Template to Display Our Form

To preserve our templates, let’s create a templates folder into our root directory. The call is non-negotiable because Django will look for HTML templates only under the folders named templates. Now our project structure is look like

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py
   firstapp/
      __init__.py
      admin.py
      apps.py
      migrations/
          __init__.py
      models.py
      tests.py
      views.py
   templates/

Set template folder configuration into TEMPLATES section in setting.py file:

'DIRS': [os.path.join(BASE_DIR,'templates')],

Inside our new folder, let’s add an index.html file.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Upload Image</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
    <div class="container">
        {% for message in messages %}
        <div class="alert alert-{{ message.tags }}  alert-dismissible fade show" role="alert">
            <strong>{{ message }}</strong>
            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
        
        {% endfor %}
        <form action="/" method="POST" enctype="multipart/form-data">
            {% csrf_token %}
            <div class="form-group">
                <label for="name">Name:</label>
                <input type="text" class="form-control" id="name" placeholder="Enter name" name="name">
            </div>
            <div class="form-group">
                <label for="email">Email:</label>
                <input type="email" class="form-control" id="email" placeholder="Enter email" name="email">
            </div>
            <div class="form-group">
                <label for="file">Picture:</label>
                <input type="file" class="form-control" id="file"  name="file">
            </div>
            
            
            <button type="submit" class="btn btn-default">Submit</button>
        </form>
    </div>
</body>
</html>

The {% csrf_token %} is another must-have for any form with action = “POST”. It is a completely unique token Django kindly creates for every customer to make sure safety while accepting requests.

View to save data

To store data and image file:


from django.shortcuts import render
from firstapp.models import Profile
from django.contrib import messages

# Create your views here.
  
def index(request):
    if request.method == 'POST':     
        name = request.POST['name']
        email = request.POST['email']
        picture = request.FILES['file']
        if Profile(name = name,email=email,profile_picture = picture).save():
            messages.success(request, "Saved successfully")
            return render(request,"index.html")
    return render(request,"index.html")

When it is saved successfully you can see in media folder and you will find your image file in user_name folder :

Folder with user name

That is it for today, hope it helps. If you have a better approach to resolve this problem please make a comment in comment section below.

If you like this article, you can buy me a coffee. Thanks!

Upload image into custom folder in Django

Leave a Reply

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

Scroll to top