ckeditor in django

hello every one
i use ckeditor so i can write posts to my users
i have a problem with that
You do not have permission to upload files.
is the error i got when try to upload photos (probably other media files)
i have such settings
proj/settings.py


CKEDITOR_5_CONFIGS = {
    'default': {
        'toolbar': [
            'heading', '|',
            'bold', 'italic', 'link', '|',
            'bulletedList', 'numberedList', '|',
            'outdent', 'indent', '|',
            'imageUpload', 'blockQuote', 'insertTable', '|',
            'undo', 'redo'
        ],
        'language': {
            'ui': 'fa',
            'content': 'fa'
        },
        'simpleUpload': {
            'uploadUrl': '/ckeditor5/image_upload/',
        },
        'height': 300,
        'width': '100%',
        'contentLanguageDirection': 'rtl',
        'removePlugins': [],
        'extraPlugins': [],
        'mediaEmbed': {
            'previewsInData': True
        },
        'image': {
            'toolbar': [
                'imageTextAlternative', '|',
                'imageStyle:alignLeft',
                'imageStyle:alignCenter',
                'imageStyle:alignRight', '|',
                'resizeImage'
            ],
            'styles': [
                'full',
                'alignLeft',
                'alignCenter',
                'alignRight'
            ]
        },
        'table': {
            'contentToolbar': [
                'tableColumn', 'tableRow', 'mergeTableCells'
            ]
        },
        'heading': {
            'options': [
                {'model': 'paragraph', 'title': 'پاراگراف', 'class': 'ck-heading_paragraph'},
                {'model': 'heading1', 'view': 'h1', 'title': 'سرتیتر 1', 'class': 'ck-heading_heading1'},
                {'model': 'heading2', 'view': 'h2', 'title': 'سرتیتر 2', 'class': 'ck-heading_heading2'},
                {'model': 'heading3', 'view': 'h3', 'title': 'سرتیتر 3', 'class': 'ck-heading_heading3'}
            ]
        }
    },
    'extends': {
        'blockToolbar': [
            'paragraph', 'heading1', 'heading2', 'heading3',
            '|',
            'bulletedList', 'numberedList',
            '|',
            'blockQuote'
        ],
        'toolbar': [
            'heading', '|',
            'outdent', 'indent', '|',
            'bold', 'italic', 'link', 'underline', 'strikethrough',
            'code', 'subscript', 'superscript', 'highlight', '|',
            'codeBlock', 'sourceEditing', 'insertImage',
            'bulletedList', 'numberedList', 'todoList', '|',
            'blockQuote', 'imageUpload', '|',
            'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor',
            'mediaEmbed', 'removeFormat',
            'insertTable', '|',
            'undo', 'redo'
        ],
        'language': {
            'ui': 'fa',
            'content': 'fa'
        },
        'simpleUpload': {
            'uploadUrl': '/ckeditor5/image_upload/',
        },
        'contentLanguageDirection': 'rtl',
        'image': {
            'toolbar': [
                'imageTextAlternative', '|',
                'imageStyle:alignLeft',
                'imageStyle:alignCenter',
                'imageStyle:alignRight', '|',
                'resizeImage'
            ]
        },
        'table': {
            'contentToolbar': [
                'tableColumn', 'tableRow', 'mergeTableCells'
            ]
        },
        'heading': {
            'options': [
                {'model': 'paragraph', 'title': 'پاراگراف', 'class': 'ck-heading_paragraph'},
                {'model': 'heading1', 'view': 'h1', 'title': 'سرتیتر 1', 'class': 'ck-heading_heading1'},
                {'model': 'heading2', 'view': 'h2', 'title': 'سرتیتر 2', 'class': 'ck-heading_heading2'},
                {'model': 'heading3', 'view': 'h3', 'title': 'سرتیتر 3', 'class': 'ck-heading_heading3'}
            ]
        }
    }
}
CKEDITOR_5_ALLOW_ALL_FILE_TYPES = True
CKEDITOR_5_UPLOAD_FILE_TYPES = ['jpeg', 'pdf', 'png', 'jpg', 'gif']
CKEDITOR_5_UPLOAD_PATH = "uploads/"
CKEDITOR_5_FILE_STORAGE = "django.core.files.storage.FileSystemStorage"
STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static']
STATIC_ROOT = BASE_DIR / 'staticfiles'

# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

and my app/forms.py be like

class PostCreateForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'text', 'cover_image', 'video']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'text': CKEditor5Widget(attrs={'class': 'django_ckeditor_5'}, config_name='default'),  # از extends به default تغییر دادم
            'cover_image': forms.FileInput(attrs={'class': 'form-control'}),
            'video': forms.FileInput(attrs={'class': 'form-control'}),
        }

class PostUpdateForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'text', 'cover_image', 'video']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'text': CKEditor5Widget(attrs={'class': 'django_ckeditor_5'}, config_name='default'),  # از extends به default تغییر دادم
            'cover_image': forms.FileInput(attrs={'class': 'form-control'}),
            'video': forms.FileInput(attrs={'class': 'form-control'}),
        }

can anyone help me fix this???

This might be an issue better raised upstream with the django-ckeditor package. My guess is the error is coming from the upload to /ckeditor5/image_upload/. Unless there’s more details in the logs about why you don’t have permission, there’s not much a generic Django support forum can do.

If you’re encountering issues with CKEditor’s default image upload (such as permission errors), you can resolve them by adding your own custom upload method before CKEditor’s URLs in your Django project’s urls.py:

# urls.py

urlpatterns = [
    path("ckeditor5/image_upload/", custom_image_upload, name="custom_image_upload"),
    path("ckeditor5/", include("django_ckeditor_5.urls")),
]

Here’s an example of a working custom image upload view (custom_image_upload):

# views.py

from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
import os

@csrf_exempt
def custom_image_upload(request):
    if not request.user.is_authenticated:
        return JsonResponse({"error": "Unauthorized"}, status=401)

    if request.method == "POST" and request.FILES.get("upload"):
        upload = request.FILES["upload"]
        upload_path = os.path.join("ckeditor_uploads", upload.name)
        upload_name = default_storage.save(upload_path, ContentFile(upload.read()))
        upload_url = default_storage.url(upload_name)
        return JsonResponse({"url": upload_url})

    return JsonResponse({"error": "Invalid request"}, status=400)

By placing your custom upload URL before the built-in CKEditor URLs, Django ensures that your custom logic is executed, resolving permission issues and giving you greater control over uploaded images.