Django集成django-ckeditor-5前端图片上传404问题求助
Django集成django-ckeditor-5图片上传前端失效问题
- 异常表现:前端页面上传图片时弹出提示
Couldn't upload file.,终端返回404错误:Not Found: /ckeditor5/image_upload/ [18/Dec/2023 15:00:22] "POST /ckeditor5/image_upload/ HTTP/1.1" 404 4276 - 特殊情况:Django admin后台中该功能可正常使用,仅前端页面失效
解决建议
- 检查URL路由层级:确认项目根
urls.py是否正确包含django_ckeditor_5的路由,而非仅在某个app的urls中配置。admin能正常使用说明路由在admin上下文生效,但前端页面可能因路由前缀问题导致404。 - 验证CSRF令牌传递:CKEditor5的图片上传是异步请求,需确保实例能获取到CSRF令牌。可在
CKEDITOR_5_CONFIGS的extends配置中添加:
或在模板中通过JS传递:"csrfToken": "{{ csrf_token }}",document.addEventListener('DOMContentLoaded', function() { CKEDITOR.ClassicEditor.create(document.querySelector('.django_ckeditor_5'), { csrfToken: '{{ csrf_token }}' }); }); - 排查自定义存储类:临时注释
CKEDITOR_5_FILE_STORAGE = "meetingapp.storage.CustomStorage"配置,使用默认存储测试是否恢复正常,确认自定义存储类是否实现了所有必要方法。 - 确认表单
enctype属性:通过浏览器开发者工具检查渲染后的表单是否保留enctype="multipart/form-data"属性,该属性是文件上传的必要条件。 - 检查MEDIA配置:确认
settings.py中MEDIA_ROOT和MEDIA_URL配置正确,开发环境需保留static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT),生产环境需配置服务器(如Nginx)处理媒体文件请求。
相关代码
meetingapp/models.py
class Meeting(models.Model): meeting_minuit_last = CKEditor5Field(config_name='extends', null=True, blank=True)
meetingapp/templates/detail.html
{% extends 'base.html' %} {% load static %} {% load crispy_forms_tags %} {% load humanize %} {% block content %} <link rel="stylesheet" href="{% static 'css/content-styles.css' %}" type="text/css"> <link rel="stylesheet" type="text/css" href="{% static 'css/meetingapp/detail.css' %}"> <div class="meeting_minuit_main mt-5 mb-5 container"> <h2>Meeting Minutes</h2> <div class="ck-content meeting-minuit mt-5 mb-5 px-5"> {% if target_meeting.meeting_minuit_last %} <p>{{ target_meeting.meeting_minuit_last | safe }}</p> {% endif %} </div> <div> <form method="POST" enctype="multipart/form-data"> {% csrf_token %} {% if not target_meeting.meeting_minuit_last %} {{ form.media }} {{ form.as_p }} <input class="btn btn-outline-secondary" type="submit" value="Submit"> {% endif %} {% if target_meeting.meeting_minuit_last %} <a href="{% url 'meetingapp:minuit_update' pk=target_meeting.pk %}" class="btn btn-outline-primary">Update Minuit</a> {% endif %} </form> </div> </div>
settings.py(CKEditor5配置部分)
customColorPalette = [ {"color": "hsl(4, 90%, 58%)", "label": "Red"}, {"color": "hsl(340, 82%, 52%)", "label": "Pink"}, {"color": "hsl(291, 64%, 42%)", "label": "Purple"}, {"color": "hsl(262, 52%, 47%)", "label": "Deep Purple"}, {"color": "hsl(231, 48%, 48%)", "label": "Indigo"}, {"color": "hsl(207, 90%, 54%)", "label": "Blue"}, ] CKEDITOR_5_FILE_STORAGE = "meetingapp.storage.CustomStorage" CKEDITOR_5_CONFIGS = { "default": { "toolbar": [ "heading", "|", "bold", "italic", "link", "bulletedList", "numberedList", "blockQuote", "imageUpload" ], }, "comment": { "language": {"ui": "en", "content": "en"}, "toolbar": [ "heading", "|", "bold", "italic", "link", "bulletedList", "numberedList", "blockQuote", ], }, "extends": { "language": "en", "blockToolbar": [ "paragraph", "heading1", "heading2", "heading3", "|", "bulletedList", "numberedList", "|", "blockQuote", ], "toolbar": [ "heading", "codeBlock", "|", "outdent", "indent", "|", "bold", "italic", "link", "underline", "strikethrough", "code", "subscript", "superscript", "highlight", "|", "bulletedList", "numberedList", "todoList", "|", "blockQuote", "insertImage", "|", "fontSize", "fontFamily", "fontColor", "fontBackgroundColor", "removeFormat", "insertTable", "sourceEditing", ], "image": { "toolbar": [ "imageTextAlternative", "|", "imageStyle:alignLeft", "imageStyle:alignRight", "imageStyle:alignCenter", "imageStyle:side", "|", "toggleImageCaption", "|" ], "styles": [ "full", "side", "alignLeft", "alignRight", "alignCenter", ], }, "table": { "contentToolbar": [ "tableColumn", "tableRow", "mergeTableCells", "tableProperties", "tableCellProperties", ], "tableProperties": { "borderColors": customColorPalette, "backgroundColors": customColorPalette, }, "tableCellProperties": { "borderColors": customColorPalette, "backgroundColors": customColorPalette, }, }, "heading": { "options": [ { "model": "paragraph", "title": "Paragraph", "class": "ck-heading_paragraph", }, { "model": "heading1", "view": "h1", "title": "Heading 1", "class": "ck-heading_heading1", }, { "model": "heading2", "view": "h2", "title": "Heading 2", "class": "ck-heading_heading2", }, { "model": "heading3", "view": "h3", "title": "Heading 3", "class": "ck-heading_heading3", }, ] }, "list": { "properties": { "styles": True, "startIndex": True, "reversed": True, } }, "htmlSupport": { "allow": [ {"name": "/.*/", "attributes": True, "classes": True, "styles": True} ] }, }, }
urls.py
urlpatterns = [ path("ckeditor5/", include('django_ckeditor_5.urls')), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
meetingapp/forms.py
class MeetingCreateDocs(ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["meeting_minuit_last"].required = False class Meta: model = Meeting fields = ['meeting_minuit_last'] labels = { 'meeting_minuit_last': '', } widgets = { "meeting_minuit_last": CKEditor5Widget( attrs={"class": "django_ckeditor_5"}, config_name="extends" ) }
内容的提问来源于stack exchange,提问作者Won Jun Jang
相关产品推荐
相关产品推荐

