Base64 is a binary-to-text encoding scheme that allows binary data, such as images, to be represented as ASCII characters. Base64 encoding is commonly used when you need to transmit binary data in JSON or text format. Base64 strings can be placed inside JSON data, making it simpler and easier to upload images.
Steps for uploading base64 images:
- Read the image file: Read the binary data of the image file you want to upload.
- Encode the image as Base64: Convert the binary image data into a Base64-encoded format using an appropriate encoding algorithm or library.
- Convert to string: Convert the Base64-encoded data into a string format, as it needs to be treated as text for transmission or storage.
- Transmit the Base64 string: Send the Base64 string over a network in JSON format to the API
In this article, we will create an API using the Django Rest framework that accepts JSON data and converts base64 strings to images. The converted image will be saved on the server.
Prerequisites:
- Basic Knowledge of Django and the Django Rest Framework
- Basic Knowledge of JavaScript
Base64 image uploading in Django steps:
- Install drf-extra-fields
- Create a model with an image fields
- Create a serializer with Base64ImageField from drf-extra-fields
- Create a function base view
- Add the view in
urls.py
and create a new route
Django Implementations of Base64Image upload:
1/5. Install drf-extra-fields:
DRF Extra Fields' Base64ImageField is a powerful addition to Django REST Framework that enables seamless handling of image uploads. It allows you to accept image data as a Base64-encoded string directly within your API payload, eliminating the need for separate file uploads. This field automatically decodes the Base64 string and saves the image file to your specified storage backend, while still providing all the benefits of DRF's serializers and validators. With Base64ImageField, you can simplify the process of accepting and processing image uploads in your Django REST API with ease and efficiency.
pip install drf-extra-fields
2/5. Create a model with an image fields:
I created a model named Article. image
field is necessary to save an image on the server disk and store the path in the database.
file_location
is a function to dynamically create a path for saving images.
from django.db import models
def file_location(instance, filename, **kwargs):
file_path = f"article/{instance.title}-{filename}"
return file_path
class Article(models.Model):
title = models.CharField(max_length=255, null=False, blank=False)
content = models.TextField(max_length=5000, null=False, blank=False)
image = models.ImageField(upload_to=file_location, null=False, blank=True)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="created_at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="updated_at")
def __str__(self):
return self.title
3/5. Create a serializer with Base64ImageField from drf-extra-fields:
We have created a serializer called ArticleBase64Serilizer
. It has three fields named title, content, and image. An image
field is a property of a model that represents an ImageField
. But in ArticleBase64Serilizer
, we override it using Bae64ImageField
. This field will accept image data as a Base64-encoded string in the API payload and automatically convert and image
from rest_framework import serializers
from myapp.models import Article
from drf_extra_fields.fields import Base64ImageField
class ArticleBase64Serilizer(serializers.ModelSerializer):
image = Base64ImageField(required=False)
class Meta:
model = Article
fields = ["title", "content", "image"]
4/5. Create a function base view:
Create a function-based view named base64_image_upload_api_view
. That receives JSON data form client and validates sending data by ArticleBase64Serilizer
, and if the data is valid, then saves it in the database and also saves an image on disk.
from rest_framework.response import Response
from rest_framework.decorators import api_view
from myapp.api.serializers import ArticleBase64Serilizer
@api_view(["POST"])
def base64_image_upload_api_view(request):
if request.method == "POST":
data = request.data
serializer = ArticleBase64Serilizer(data=data)
if serializer.is_valid():
article = serializer.save()
data = serializer.data
return Response(data=data)
return Response(serializer.errors, status=400)
5/5. Add the view in urls.py
and create a new route:
from myapp.api.views import base64_image_upload_api_view
urlpatterns = [
path(
"api/base64_image_upload",
base64_image_upload_api_view,
name="base64_image_upload",
),
]
Demo base64 image with JSON for testing API:
{
"title" : "Testing title",
"content" : "demo content",
"image" : "<base64 string>"
}
OR
{
"title" : "Testing title",
"content" : "demo content",
"image" : "data:image/png;base64, <base64 string>"
}
You can use online image to base64 converter tools to generate base64 string for tesing API.
JavaScript Steps:
- Create a templates/html file with image uploading form
- Create a function for image to base64 convert
- Create an
axios
request for uploading base64 image - Create a view in
views.py
- Add the view in
urls.py
and create a new route
JavaScript base64 image uploading implementations:
1/5. Create a templates/html file with image uploading form:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Base64 Image Upload</title>
<style>
body {
padding: 1rem;
}
form {
width: 50vw;
height: fit-content;
}
</style>
</head>
<body>
<form method="POST" onsubmit="image_to_base64(event)">
<label for="title">Title</label>
<br>
<input type="text" name="title" id="title" placeholder="title">
<br>
<br>
<label for="content">Content</label>
<br>
<textarea name="content" id="content" placeholder="Content"></textarea>
<br>
<br>
<label for="image">Image</label>
<input type="file" name="image" id="image" accept="image/*">
<br>
<button type="submit">Submit</button>
</form>
</body>
</html>
2/5. Create a function for image to base64 convert
function image_to_base64(event) {
event.preventDefault();
var file = document.getElementById("image").files[0];
var reader = new FileReader();
reader.onloadend = function () {
console.log(reader.result)
upload_data(reader.result)
}
var text = reader.readAsDataURL(file);
}
3/5. Create an axios
request for uploading base64 image:
function upload_data(base64_string) {
event.preventDefault();
var title = document.getElementById("title").value
var content = document.getElementById("content").value
var json_data = {
"title": title,
"content": content,
"image": base64_string
}
axios.post(
'/api/base64_image_upload',
json_data, {
headers: {
'Content-Type': 'application/json'
},
xsrfCookieName: 'csrftoken',
xsrfHeaderName: 'X-CSRFTOKEN'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
4/5. Create a view in views.py
:
def upload_base64_image_view(request):
return render(request, "base64_image_upload.html", {})
5/5. Add the view in urls.py
and create a new route:
from myapp.api.views import base64_image_upload_api_view
from myapp.views import upload_base64_image_view
urlpatterns = [
path(
"api/base64_image_upload",
base64_image_upload_api_view,
name="base64_image_upload",
),
path("base64_image", upload_base64_image_view, name="base64_image"),
]
Full Code:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Base64 Image Upload</title>
<style>
body {
padding: 1rem;
}
form {
width: 50vw;
height: fit-content;
}
</style>
</head>
<body>
<form method="POST" onsubmit="image_to_base64(event)">
<label for="title">Title</label>
<br>
<input type="text" name="title" id="title" placeholder="title">
<br>
<br>
<label for="content">Content</label>
<br>
<textarea name="content" id="content" placeholder="Content"></textarea>
<br>
<br>
<label for="image">Image</label>
<input type="file" name="image" id="image" accept="image/*">
<br>
<button type="submit">Submit</button>
</form>
<!-- Axios -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.4.0/axios.min.js"
integrity="sha512-uMtXmF28A2Ab/JJO2t/vYhlaa/3ahUOgj1Zf27M5rOo8/+fcTUVH0/E0ll68njmjrLqOBjXM3V9NiPFL5ywWPQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
function upload_data(image) {
event.preventDefault();
var title = document.getElementById("title").value
var content = document.getElementById("content").value
var json_data = {
"title": title,
"content": content,
"image": image
}
axios.post(
'/api/base64_image_upload',
json_data, {
headers: {
'Content-Type': 'application/json'
},
xsrfCookieName: 'csrftoken',
xsrfHeaderName: 'X-CSRFTOKEN'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
function image_to_base64(event) {
event.preventDefault();
var file = document.getElementById("image").files[0];
var reader = new FileReader();
reader.onloadend = function () {
console.log(reader.result)
upload_data(reader.result)
}
var text = reader.readAsDataURL(file);
}
</script>
</body>
</html>