Base64 image upload django rest framework

Last updated: Feb. 4, 2024

Django provides a versatile and secure approach for image uploading through Django Rest Framework (DRF). Two commonly used methods for image uploading in DRF are

  1. multipart/form-data:
  2. Base64

In this article, I explain how to upload an image with a base64-encoded string using the Django Rest Framework.

Features:

  • Single image upload by multipart/form-data
  • Also JavaScript implementation
    • Use Axios library for POST request
    • Use Ajax for post request
  • Secure:
    • CSRF protection

Setup django project for image uploading

Install required packages:

Make sure you have Django and Django Rest Framework installed:

pip install django djangorestframework drf-extra-fields

 

Configure Django settings:

Add 'rest_framework' and 'yourapp' (replace with your app name) to INSTALLED_APPS in your settings.py:

# yourprojectname/settings.py

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'drf_extra_fields',
    'yourappname',
]

# Add 'rest_framework.parsers.MultiPartParser' to enable handling multipart/form-data requests
REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.MultiPartParser',
    ),
}

 

Configure Django MEDIA_ROOT and MEDIA_URL:

Configure your Django settings to define the MEDIA_ROOT and MEDIA_URL, specifying where uploaded media files will be stored and how they will be accessed.

# yourproject/settings.py

MEDIA_URL = "/media/"

MEDIA_ROOT = os.path.join(BASE_DIR, "media")

 

Model for Image Upload:

Define a model in your models.py file to handle image uploads. Use ImageField for storing images:

# yourappname/models.py

from django.db import models

class ImageModel(models.Model):
    title = models.CharField(max_length=255)
    description = models.TextField()
    image = models.ImageField(upload_to='images/')

 

Don't forget to run migrations:

python manage.py makemigrations
python manage.py migrate

 

Serializer:

Create a serializer in your serializers.py file to convert your model instances to JSON and vice versa:

# yourappname/serializers.py

from drf_extra_fields.fields import Base64ImageField
from rest_framework import serializers
from .models import ImageModel

class ImageModelSerializer(serializers.ModelSerializer):
    image = Base64ImageField(required=False)

    class Meta:
        model = ImageModel
        fields = ('id', 'title', 'description', 'image')

 

 

Views:

Create a view in your views.py file to handle image uploads:

Class base view

# yourappname/views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import ImageModel
from .serializers import ImageModelSerializer

class Base64ImageView(APIView):
    def post(self, request, *args, **kwargs):
        serializer = ImageModelSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

OR:

Function base view

from rest_framework.response import Response
from rest_framework.decorators import api_view
from .models import ImageModel
from .serializers import ImageModelSerializer

@api_view(["POST"])
def base64_image_image_view(request):
    serializer = ImageModelSerializer(data=request.data)
    if serializer.is_valid():
        return Response(
            data={
                "response": "success",
                "msg": "Successfully image uploaded"
            }
        )
    else:
        return Response(
            data=serializer.errors
            status=400
        )

 

URL Configuration:

Configure your URLs in urls.py to include the DRF view:

Class base view

# yourappname/urls.py

from django.urls import path
from .views import Base64ImageView

urlpatterns = [
    path('base64image/', Base64ImageView.as_view(), name='base64-image-upload'),
    # Add more patterns as needed
]

OR:

Function base view

# yourappname/urls.py

from django.urls import path
from .views import base64_image_image_view

urlpatterns = [
    path('base64image/', base64_image_image_view, name='base64-image-upload'),
    # Add more patterns as needed
]

 

Include these URLs in your project's urls.py:

# yourproject/urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('yourapp.urls')),
]

 

Runserver:

Run the development server:

python manage.py runserver

Visit http://localhost:8000/api/base64image/ in your browser or use a tool like curl or Postman to send POST requests with image files.

 

 

Implement frontend with JavaScript for image uploading

To handle image uploading using  forms and JavaScript Axios and Ajax, you can create a simple form in your Django templates and use Axios/Ajax to send the form data to your DRF API endpoint. Here's a step-by-step guide

 

views.py:

# yourappname/views.py

from django.shortcuts import render

def image_upload_view(request):
    return render(request, 'image_upload.html')

 

And a corresponding URL pattern in urls.py:

urls.py:

# yourappname/urls.py

from django.urls import path
from .views import image_upload_view

urlpatterns = [
    path('image_upload/', image_upload_view, name='image_upload_view'),
    # Add more patterns as needed
]

 

Now, create the template file for the frontend:

templates/image_upload.html with Axios library:

<!-- yourappname/templates/image_upload.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Upload</title>
</head>
<body>
    <h2>Image Upload</h2>
    <form id="uploadForm">
        <label for="titleInput">Title:</label>
        <input type="text" id="titleInput" name="title" required>
        <br>
        <label for="descriptionInput">Description:</label>
        <textarea id="descriptionInput" name="description" required></textarea>
        <br>
        <label for="imageInput">Select Image:</label>
        <input type="file" id="imageInput" name="image" accept="image/*" required>
        <br>
        <button type="submit">Upload</button>
    </form>

    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
        document.getElementById('uploadForm').addEventListener('submit', function (e) {
            e.preventDefault();

            const form = e.target;
            const formData = new FormData(form);

            axios.post('/yourapi/base64image/', formData)
                .then(response => {
                    if (response.data.success) {
                        alert('Image uploaded successfully!');
                        // Add further handling or redirection as needed
                    } else {
                        alert('Image upload failed. Please check the form and try again.');
                    }
                })
                .catch(error => {
                    console.error('Error during image upload:', error);
                    alert('Image upload failed. Please try again later.');
                });
        });
    </script>
</body>
</html>

templates/image_upload.html with Ajax:

<!-- yourappname/templates/image_upload.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Upload</title>
</head>
<body>
    <h2>Image Upload</h2>
    <form id="uploadForm">
        <label for="titleInput">Title:</label>
        <input type="text" id="titleInput" name="title" required>
        <br>
        <label for="descriptionInput">Description:</label>
        <textarea id="descriptionInput" name="description" required></textarea>
        <br>
        <label for="imageInput">Select Image:</label>
        <input type="file" id="imageInput" name="image" accept="image/*" required>
        <br>
        <button type="button" onclick="uploadImage()">Upload</button>
    </form>

    <script>
        function uploadImage() {
            const form = document.getElementById('uploadForm');
            const formData = new FormData(form);

            const xhr = new XMLHttpRequest();
            xhr.open('POST', '/base64image/', true);

            xhr.onload = function () {
                if (xhr.status === 201) {
                    alert('Image uploaded successfully!');
                    // Add further handling or redirection as needed
                } else {
                    alert('Image upload failed. Please check the form and try again.');
                }
            };

            xhr.onerror = function () {
                console.error('Error during image upload.');
                alert('Image upload failed. Please try again later.');
            };

            xhr.send(formData);
        }
    </script>
</body>
</html>


In conclusion, secure implementation of base64 image uploading in Django involves careful consideration of various security aspects. Developers should prioritize data integrity and validation, utilize CSRF protection, ensure secure transmission with HTTPS, implement input sanitization, enforce file upload restrictions, employ proper authentication and authorization checks, establish comprehensive logging and monitoring, vet third-party libraries for security, and conduct regular security audits. These measures collectively contribute to a robust and secure base64 image uploading process, mitigating potential vulnerabilities and ensuring the overall safety of the application.