Recently I was working on Djangoproject.in website and had issue with creating a image upload functionality.
So decide to create this article to show everyone out there, how it can be done for create and update in Django.
- Make sure you have sign-up for tinymce and https://www.tiny.cloud/auth/signup
- Logged in https://www.tiny.cloud/auth/login
- Also added local, URL to approved domain list like below image
- Make sure to add your script link into JavaScript section
<script src="https://cdn.tiny.cloud/1/your-key/tinymce/7/tinymce.min.js" referrerpolicy="origin"></script>
- After this lets move to JavaScript code
tinymce.init({ selector: '#editor', plugins: 'anchor autolink charmap codesample emoticons image link lists media searchreplace table visualblocks wordcount checklist mediaembed casechange export formatpainter pageembed linkchecker a11ychecker tinymcespellchecker permanentpen powerpaste advtable advcode editimage advtemplate ai mentions tinycomments tableofcontents footnotes mergetags autocorrect typography inlinecss markdown', toolbar: 'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | link image media table mergetags | addcomment showcomments | spellcheckdialog a11ycheck typography | align lineheight | checklist numlist bullist indent outdent | emoticons charmap | removeformat', tinycomments_mode: 'embedded', tinycomments_author: 'Rohan Yeole', images_upload_url: 'editor-image/add/', ai_request: (request, respondWith) => respondWith.string(() => Promise.reject("See docs to implement AI Assistant")), setup: function (editor) { // Set content when editor is initialized editor.on('init', function () { if (form.classList.contains('update-blog')) { tinymce.activeEditor.setContent(descriptionField.value, { format: 'html' }); } }); } });
This Code snippet doing following work for us
- Initialize the tinymce with selector
#editor
- sets tinymce plugins and toolbar with needed functionality
- added author name, make sure to add yours
- The Line
images_upload_url: 'editor-image/add/',
added this option to make POST request toeditor-image/add/
URL, this URL will get append to current URL of page, E.g - If current URL of page ishttp://127.0.0.1:8000/create-blog/
then your image upload URL will becomehttp://127.0.0.1:8000/create-blog/editor-image/add/
- Lastly if the form contains
update-blog
then we know its a update form, since we will be using same script for update and create of blog
Updating urls.py
urlpatterns = [ path('update/<int:id>/blog/', views.updateBlog, name='updateBlog'), path('create-blog/', views.createBlog, name='createBlog'), path('update/<int:id>/blog/editor-image/add/', views.updateImageFromEditor, name="updateImageFromEditor"), path('create/editor-image/add/', views.imageFromEditor, name="imageFromEditor"), ]
- First URL is for updating the blog
- Second for creating blog
- The last two are for our tinymce to upload the image.
I wont go into first two since I'm expecting you must have implemented them.
lets create common python function which take file and its file suffix, upload to our media/blog folder, finally returns us a file URL -
def saveImage(file, file_name_suffix): file_path = os.path.join(settings.MEDIA_ROOT, 'blog', file.name) if os.path.exists(file_path): file.name = str(uuid4()) + '.' + file_name_suffix file_path = os.path.join(settings.MEDIA_ROOT, 'blog', file.name) # Check file extension with open(file_path, 'wb+') as f: for chunk in file.chunks(): f.write(chunk) return os.path.join(settings.MEDIA_URL, 'blog', file.name)
After creating this function lets add code for create blog upload image for our tinymce editor like below -
following Django view get image from files, checks for valid type and calls our common function which return us image URL
@csrf_exempt def imageFromEditor(request): if request.method == 'POST': image_file = request.FILES.get('file', None) if image_file: file_name_suffix = image_file.name.split('.')[-1] if file_name_suffix not in ['jpg', 'png', 'gif', 'jpeg']: return JsonResponse({"error": f"Wrong file suffix ({file_name_suffix}), supported are .jpg, .png, .git, .jpeg"}) else: location = saveImage(image_file, file_name_suffix) return JsonResponse({'location': location}) return JsonResponse({'error': 'No file found'}) return JsonResponse({'error': 'Invalid request'}, status=400)
Now this is how update blog look like, its mostly similar except here we are validating if blog exists in Database.@csrf_exempt def updateImageFromEditor(request, id): if request.method == 'POST': instance = models.Blog.objects.get(id=id) if not instance: return JsonResponse({"error": "Invalid blog update"}) image_file = request.FILES.get('file', None) if image_file: file_name_suffix = image_file.name.split('.')[-1] if file_name_suffix not in ['jpg', 'png', 'gif', 'jpeg']: return JsonResponse({"error": f"Wrong file suffix ({file_name_suffix}), supported are .jpg, .png, .git, .jpeg"}) else: location = saveImage(image_file, file_name_suffix) return JsonResponse({'location': location}) return JsonResponse({'error': 'No file found'}) return JsonResponse({'error': 'Invalid request'}, status=400)
That's it- Initialize the tinymce with selector