Integrating EditorJS with Django

Abhik
Analytics Vidhya
Published in
5 min readOct 29, 2020

--

EditorJS might give writers in your blog the same feel writers in medium get,more or less. Want to integrate Django and editorJS together for a blog or something similar? This article might help you.

DJango With EditorJS

Assumption :

You already have a Ajango project and a app where you are going to use editorjs

Step 1 : Installing django editorjs

pip install django-editorjs

Now add django_editorjs to INSTALLED_APPS in settings.py (Note the underscore here)

Step 2 : Creating the model

Now before we create the model , let me inform you that to upload images you need to setup your own file uploading solution (I have covered that too !)

So here I will create a Post model where I will first import EditorJsField

from django_editorjs import EditorJsField

then I will create fields for Post, the body field will have EditorJsField .

Post model

But if you need to have images inside that post then :

Post Model with images for editorJs enabled

So in this model we have editorjs_config which will have custom settings for image.

Notice :

1. I have two urls for byFile and byUrl fields in endpoints in config of Image. we will be creating those urls from scratch.

2. I also have additionalRequestHeaders field which has a array of objects ,though only one object is there . This object has :

Content-Type:’multipart/form-data’

This header is necessary for uploading images.

Now make migrations and migrate.

Images when uploaded to editorJS will be pushed to the server , if server returns success only then we can have that image in the editor space.

Step 3 : Handling the image upload

First import this in views.py

Import in views.py

Then write this function

Image upload

Explanation of the above code :

  • @requires_csrf_token helps us dodge any csrf error that might occur because we are not using any form to upload images so we cannot set any csrf token/cookie thus this is an alternative, works similarly to csrf_protect, but never rejects an incoming request.
  • whenever image is uploaded by editorJs they send a request which has images object in it.This images has the image file
  • to get the filename we need to convert the object to string then split it and the first part will be name while the second part will be extension
  • then we save the file and get the file url
  • then we return Json response in this format (mandatory )

In urls.py for post write this: csrf_exempt is needed for

urls.py

Also:

settings.py

Please do add MEDIA_ROOT & MEDIA_URL in your settings and in urls.py add :

Thats it ! We have done it!

Full Code : https://github.com/abhik-b/django-editorjs-tutorial

For a much detailed explanation watch this :

Video Tutorial

Finally this is the model for link fetching, uploading files and images

Similarly view for file upload

file upload view

For link fetching please install pip install bs4 inside virtual environment and then write this view to extract metadata from any link and display open graph for that.

link fetching view

Now if you have watched the video on how to render the data from body field in html and js then this the full js code

<p id="post-body"></p><script>window.addEventListener("DOMContentLoaded", () => {const postBody = document.getElementById("post-body");console.log("{{post.body|escapejs}}");let body = JSON.parse("{{post.body|escapejs}}");let blocks = body.blocks;for (let index = 0; index < blocks.length; index++) {switch (blocks[index].type) {case "Header":let head = document.createElement(`h${blocks[index].data.level}`);head.textContent = blocks[index].data.text;postBody.appendChild(head);break;case "Image":let div = document.createElement("div");let image = document.createElement("img");let caption = document.createElement("h5");image.src = `${blocks[index].data.file.url}`;caption.textContent = blocks[index].data.caption;div.appendChild(image);div.appendChild(caption);postBody.appendChild(div);break;case "List":let list;if (blocks[index].data.style == "unordered") {list = document.createElement("ul");} else {list = document.createElement("ol");}for (const item in blocks[index].data.items) {let li = document.createElement("li");li.textContent = blocks[index].data.items[item];list.appendChild(li);}postBody.appendChild(list);break;case "Raw":let blockquote = document.createElement("blockquote");let code = document.createElement("code");let pre = document.createElement("pre");pre.textContent = blocks[index].data.html;pre.style.background = "#131313";pre.style.color = "#dddddd";pre.style.padding = "15px";code.appendChild(pre);postBody.appendChild(code);break;case "Attaches":let parent = document.createElement("div");let a = document.createElement("a");let name = document.createElement("h3");let size = document.createElement("h3");a.href = `${blocks[index].data.file.url}`;a.textContent = `Downlod ${blocks[index].data.file.extension}`;name.textContent = blocks[index].data.file.name;size.textContent = blocks[index].data.file.size;parent.innerHTML = `<a href="${blocks[index].data.file.url}" download>Download</a>`;parent.appendChild(a);parent.appendChild(name);parent.appendChild(size);postBody.appendChild(parent);break;case "paragraph":const p = document.createElement("p");p.innerHTML = blocks[index].data.text;postBody.appendChild(p);case "Link":let parent2 = document.createElement("div");let a2 = document.createElement("a");if (blocks[index].data.meta.description) {let desc = document.createElement("p");desc.textContent = blocks[index].data.meta.description;parent2.appendChild(desc);}if (blocks[index].data.meta.title) {let title = document.createElement("h3");title.textContent = blocks[index].data.meta.title;parent2.appendChild(title);}if (blocks[index].data.meta.image.url !== "") {let img = document.createElement("img");img.src = blocks[index].data.meta.image.url;parent2.appendChild(img);}a2.href = blocks[index].data.link;parent2.appendChild(a2);postBody.appendChild(parent2);default:break;}}});</script>

However if you are planning to use this for production, then please find a better way to handle image uploading since we are exempting csrf tokens for images, even though we are using requires_csrf_token as a protective measure still…

I will update this article if I find any better solution !

Hope this helps 🎉

--

--

Abhik
Analytics Vidhya

Interested in frontend developement & UI design