Integrating EditorJS with Django
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.
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 .
But if you need to have images inside that post then :
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
Then write this function
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
Also:
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 :
Finally this is the model for link fetching, uploading files and images
Similarly view for file upload
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.
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 !