-
-
Notifications
You must be signed in to change notification settings - Fork 316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tinymce django image upload #356
Comments
You need to write the JS uploader and then the Django view to handle the upload yourself. Here's what I did to achieve this where I use Django Storages as the backend but I use default_storage to write the file to the backend so everything should work for you with the exception of the full URL to the uploaded file. Step 1.
The first is the path to which you would like the javascript to make the POST. The 2nd is the name of the javascript function to handle the upload Step 2 Add the below into your settings.py to tell it yo include two additional JS file. I'm using the jsdelivr CDN hosted version for the above package
The second file is holds the custom JS file upload handler I will post below. Step 3.
Step 4 The key part is to return a JSONResponse with the location of the image you just uploaded. In my case I am using Django Storages to store files on S3 but I serve them from AWS Cloudfront using a custom domain that I have set within settings.py so I append that to the start
Now I can upload images using the TinvMCE plugin ensuring that CSRF checks are made |
Althought its unsecure, you could exempt the view images_upload_url from csrf token. Take a look at this: https://docs.djangoproject.com/en/4.1/howto/csrf/#disabling-csrf-protection-for-just-a-few-views |
I did not test any of this this but hopefully someone could make a PR from this. When using Django's CsrfViewMiddleware to include a CSRF token in your Django form to protect it from Cross-Site Request Forgery attacks, it can be tricky to perform file uploads when the user wants to upload images or other files that do not have an appropriate HTML form. Here's an alternative approach to include the CSRF token in the upload request when using django-tinymce:
In your Django URLconf, add the following URL pattern:
In this example, we're adding a URL pattern that maps the URL /tinymce/upload/ to the handle_upload view provided by Django-tinymce. We're also using the csrf_exempt decorator to disable CSRF protection for this view. In your TinyMCE configuration, add the following options:
In this example, we're setting the image_upload_url option to the URL pattern we defined earlier (reverse('tinymce_upload')), and the image_upload_method option to 'POST'. Note that by using csrf_exempt, we're disabling CSRF protection for the handle_upload view. If you want to enable CSRF protection for this view, you'll need to use a different approach, such as including the CSRF token in the upload request.
In your tiny_mce_init.js file, update the file_picker_callback option to use the tinymce_upload_handler function we defined earlier and set the upload_url option to the URL of the file upload view you just created. Here's an example:
In your urls.py, add a URL pattern that will map to the view you just created. Here's an example:
In your template or JavaScript file, use the tinymce.init function to initialize TinyMCE with a custom image_upload_url that corresponds to the URL pattern you just added to your urls.py.
Test your implementation by creating a new Post or Page in your site that contains an image. When you click the image button in TinyMCE's toolbar, you should see an "Upload" tab that allows you to select an image file and upload it to your Django application. Once the upload is complete, the image should be inserted into the text editor. |
Hi there, I used @StevenMapes solution and tried to improve it a little bit. Thanks to him
TINYMCE_DEFAULT_CONFIG = {
"height": 490,
"promotion": False,
"menubar": False,
"width": "full",
"plugins": "advlist autolink lists link image media charmap preview anchor pagebreak directionality emoticons fullscreen table visualblocks code codesample",
"toolbar1": "fullscreen preview | undo redo | fontfamily fontsize | numlist bullist accordion | indent outdent ltr rtl | blocks",
"toolbar2": (
"pagebreak footnotes | bold italic underline strikethrough subscript superscript | formatpainter backcolor forecolor removeformat |"
"align lineheight | charmap emoticons link image media table codesample | code visualblocks"
),
# Add these two lines
"images_upload_url": "/tinymce/upload/",
"file_picker_callback": "filePickerCallback",
} right after that add this TINYMCE_EXTRA_MEDIA = {
"css": {
"all": [],
},
"js": [
"https://cdn.jsdelivr.net/npm/[email protected]/dist/js.cookie.min.js",
# Path to the script
"admin/js/tinymce-upload.js", # change it accordingly
],
}
function filePickerCallback(cb, value, meta) {
var input = document.createElement("input");
input.setAttribute("type", "file");
if (meta.filetype == "image") {
input.setAttribute("accept", "image/*");
}
input.onchange = function () {
var file = this.files[0];
var formData = new FormData();
formData.append("file", file);
var xhr = new XMLHttpRequest();
xhr.open("POST", "/tinymce/upload/"); // change this accordingly
xhr.setRequestHeader("X-CSRFToken", Cookies.get("csrftoken"));
xhr.onload = function () {
if (xhr.status < 200 || xhr.status >= 300) {
console.error("Upload failed with status: " + xhr.status);
return;
}
var json = JSON.parse(xhr.responseText);
if (!json || typeof json.location !== "string") {
console.error("Invalid JSON response: " + xhr.responseText);
return;
}
cb(json.location, { title: file.name });
};
xhr.onerror = function () {
console.error("Upload failed.");
};
xhr.send(formData);
};
input.click();
}
from core.models import File
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def tinymce_upload(request):
"""Upload file to AWS S3 and return the location."""
if request.method != "POST" or not request.FILES.get("file"):
return JsonResponse({"error": "Invalid request"}, status=400)
file = request.FILES["file"]
file_instance = File.objects.create(file=file)
return JsonResponse({"location": file_instance.file.url}) Note: Here I configured
STORAGES = {
"default": {
"BACKEND": "storages.backends.s3.S3Storage",
},
"staticfiles": {
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
},
}
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
AWS_S3_ENDPOINT_URL = os.getenv("AWS_S3_ENDPOINT_URL")
AWS_STORAGE_BUCKET_NAME = os.getenv("AWS_STORAGE_BUCKET_NAME")
AWS_SERVICE_NAME = os.getenv("AWS_SERVICE_NAME", "s3")
AWS_S3_FILE_OVERWRITE = False if os.getenv("AWS_S3_FILE_OVERWRITE") == "False" else True
AWS_LOCAL_STORAGE = BASE_DIR / os.getenv("AWS_LOCAL_STORAGE", "aws")
AWS_DEFAULT_ACL = "public-read"
AWS_QUERYSTRING_AUTH = False in one of your applications in class File(models.Model):
file = models.FileField()
def __str__(self):
return self.name You can use Hope it helps! ✌️ |
i wanna know how upload image
i already set tinymce.init and the problem is the images_upload_url
how i can upload them and it's require csrf too :(
help meeee
The text was updated successfully, but these errors were encountered: