استفاده از React CKEditor 5 با جنگو (DRF)

Summarize this content to 400 words in Persian Lang می خواستم با شما در میان بگذارم که چگونه این مشکل CKEditor را انجام دادم که مدت هاست در یکی از پروژه هایم روی آن کار می کردم و در نهایت موفق به حل آن شدم. صادقانه بگویم، من نتوانستم اطلاعات کافی یا وبلاگ خوبی در مورد این موضوع پیدا کنم. به همین دلیل به فکر افتادم که یک وبلاگ کوچک بنویسم که برای شما مفصل و آسان باشد.
به طور معمول، استفاده از آن چندان دشوار نیست، اما قسمت آپلود تصویر کمی مرا آزار داد. از آنجایی که سعی می کردم این کار را از طریق API انجام دهم، متوجه شدم که باید کمی با تنظیمات بازی کنم.
پس بیایید ببینیم چگونه این کار را انجام دادم.
پیکربندی جنگو:
ابتدا باید فریمورک django rest را دانلود کنیم:
pip install djangorestframework
#settings.py
INSTALLED_APPS = [
…
“rest_framework”,
“rest_framework.authtoken”,
]
REST_FRAMEWORK = {
‘DEFAULT_AUTHENTICATION_CLASSES’: [
‘rest_framework.authentication.TokenAuthentication’,
‘rest_framework.authentication.BasicAuthentication’,
]
}
از آنجایی که ما از CKEditor در React استفاده می کنیم، بیایید تنظیمات لازم را برای جلوگیری از خطاهای CORS انجام دهیم.
pip install django-cors-headers
#settings.py
INSTALLED_APPS = [
…,
“corsheaders”,
…,
]
MIDDLEWARE = [
…,
“corsheaders.middleware.CorsMiddleware”,
“django.middleware.common.CommonMiddleware”,
…,
]
#localhost:5173 my react app url
CSRF_TRUSTED_ORIGINS = [“http://localhost:5173”]
CORS_ORIGIN_WHITELIST = [
“http://localhost:5173”,
]
CORS_ORIGIN_ALLOW_ALL = False
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_METHODS = [
“DELETE”,
“GET”,
“OPTIONS”,
“PATCH”,
“POST”,
“PUT”,
]
CORS_ALLOW_HEADERS = [
“accept”,
“accept-encoding”,
“authorization”,
“content-type”,
“dnt”,
“origin”,
“user-agent”,
“x-csrftoken”,
“x-requested-with”,
“token”,
]
حالا بیایید تنظیمات لازم را برای CKEditor انجام دهیم. هم برای عملکرد کاربر و هم برای توسعه دهنده، من می خواستم از CKEditor در خود جنگو استفاده کنم. تنظیماتی که ما در اینجا انجام دادیم برای تعیین مسیر زمانی است که کاربر تصویری را در سمت React آپلود می کند و اطمینان حاصل می کند که جنگو این اجازه را می دهد.
#settings.py
INSTALLED_APPS = [
…,
“ckeditor”,
“ckeditor_uploader”,
…,
]
CKEDITOR_UPLOAD_PATH = “uploads/”
CKEDITOR_IMAGE_BACKEND = “pillow”
CKEDITOR_STORAGE_BACKEND = ‘django.core.files.storage.FileSystemStorage’
CKEDITOR_CONFIGS = {
“default”: {
“filebrowserImageUploadUrl”: “/ckeditor/upload/”,
},
}
#urls.py:
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path(“ckeditor/upload/”, uploadFile, name=”ckeditor_upload”),
path(“ckeditor/”, include(“ckeditor_uploader.urls”)),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
ما تنظیمات خود را در جنگو به پایان رساندیم، اکنون به قسمت اصلی یعنی React می رویم.
ابتدا اجازه دهید CKEditor-u را در پروژه خود قرار دهیم.
npm install –save @ckeditor/ckeditor5-react @ckeditor/ckeditor5-build-classic
// AddBlog.jsx
import React, { Component } from ‘react’;
import { CKEditor } from ‘@ckeditor/ckeditor5-react’;
import ClassicEditor from ‘@ckeditor/ckeditor5-build-classic’;
خوب، ما در واقع می توانیم از CKEditor با این استفاده کنیم، اما برای آپلود تصاویر باید تنظیمات بیشتری انجام دهیم.
ابتدا بیایید یک کامپوننت ایجاد کنیم و کدهای لازم را در اینجا بنویسیم.
// components/CustomUploadAdapter.jsx
class CustomUploadAdapter {
constructor(loader) {
this.loader = loader;
this.url=”http://127.0.0.1:8000/ckeditor/upload/”; // Here we define the path we specified in django
}
upload() {
return this.loader.file.then(file => new Promise((resolve, reject) => {
const data = new FormData();
data.append(‘upload’, file);
const token = localStorage.getItem(‘token’);
if (!token) {
reject(‘No token found. User must be logged in to upload images.’);
return;
}
fetch(this.url, {
method: ‘POST’,
body: data,
headers: {
“Authorization”: `Token ${token}`
},
})
.then((response) => response.json())
.then(response => {
if (response.url) {
resolve({
default: response.url
});
} else {
reject(response.error ? response.error.message : ‘An error occurred while uploading the file.’);
}
})
.catch(error => {
reject(‘An error occurred while uploading the file: ‘ + error.message);
});
}));
}
abort() {
console.log(‘Wasted…’);
}
}
export default CustomUploadAdapter;
بخش مهمی از این کد که باید به آن توجه کنید استفاده صحیح از توکن کاربر وارد شده و مشخص کردن صحیح آن است. از آنجایی که در سایت من قسمت ورود وجود دارد، این تنظیمات بر اساس آن نوشته شده است.
عالی، اکنون در آخرین قسمت هستیم، اکنون که تمام تنظیمات لازم را انجام داده ایم، می توانیم صفحه AddBlog را به طور کامل ویرایش کنیم.
// AddBlog.jsx
import React, { Component } from ‘react’;
import { CKEditor } from ‘@ckeditor/ckeditor5-react’;
import ClassicEditor from ‘@ckeditor/ckeditor5-build-classic’;
import CustomUploadAdapter from ‘../components/CustomUploadAdapter’; // Let’s show the path to the Adapter code we prepared.
const AddBlogs = () => {
const handleChange = (e) => {
const { name, value } = e.target;
setBlogData(prevState => ({
…prevState,
[name]: value
}));
};
const handleCkeditorState = (language, _event, editor) => {
const data = editor.getData();
setBlogData(prevState => ({
…prevState,
[`${language}_content`]: data
}));
};
const handleContentBeforeLoad = (content) => {
const backendBaseURL = ‘http://127.0.0.1:8000’;
return content.replace(/src=”\/media\/(.*?)”/g, `src=”${backendBaseURL}/media/$1″`);
};
const onEditorInit = (editor) => {
editor.plugins.get(‘FileRepository’).createUploadAdapter = (loader) => {
return new CustomUploadAdapter(loader);
};
};
return (
<div className=”addblog”>
<h2>{id ? ‘Blog Update’ : ‘Add new blog’}</h2>
<form onSubmit={handleSubmit}>
<div>
<label htmlFor=”en_content”>En Content:</label>
<CKEditor
editor={ClassicEditor}
data={handleContentBeforeLoad(blogData.en_content)}
onChange={(event, editor) => handleCkeditorState(‘en’, event, editor)}
onReady={onEditorInit}
config={{
extraPlugins: [CustomUploadAdapter],
ckfinder: {
uploadUrl: ‘http://127.0.0.1:8000/ckeditor/upload/’
}
}}
/>
</div>
<div className=”buttons”>
<button id=’dashboard__submit__btn’ type=”submit”>{id ? ‘Update’ : ‘Add’}</button>
{id && (
<button id=’dashboard__delete__btn’ type=”button” onClick={handleDelete}><i className=”fa-solid fa-trash”></i></button>
)}
</div>
</form>
</div>
);
}
export default AddBlogs;
نتیجه گیری
لازم نیست نگران آن باشید، می توانید به راحتی آن را پیدا کنید و پس از جستجوی دقیق آن را تعمیر کنید. حداکثر، در مورد اینکه کدام نسخه از ابزارها ناسازگار هستند، خطا دریافت خواهید کرد.
قبل از رفتن… اگر سوالی/پیشنهاد/فکری دارید، یک خط زیر را برای من بگذارید. 🖋️
و اگر از این کار لذت بردید، با یک ایموجی زیبا (🤯❤️🔥) به ما بگویید چه احساسی داشتید و فراموش نکنید که برای بهروزرسانیهای بعدی دنبال کنید.
این از من است. به زودی صحبت خواهیم کرد!
– TheHormat ♟️
می خواستم با شما در میان بگذارم که چگونه این مشکل CKEditor را انجام دادم که مدت هاست در یکی از پروژه هایم روی آن کار می کردم و در نهایت موفق به حل آن شدم. صادقانه بگویم، من نتوانستم اطلاعات کافی یا وبلاگ خوبی در مورد این موضوع پیدا کنم. به همین دلیل به فکر افتادم که یک وبلاگ کوچک بنویسم که برای شما مفصل و آسان باشد.
به طور معمول، استفاده از آن چندان دشوار نیست، اما قسمت آپلود تصویر کمی مرا آزار داد. از آنجایی که سعی می کردم این کار را از طریق API انجام دهم، متوجه شدم که باید کمی با تنظیمات بازی کنم.
پس بیایید ببینیم چگونه این کار را انجام دادم.
پیکربندی جنگو:
- ابتدا باید فریمورک django rest را دانلود کنیم:
pip install djangorestframework
#settings.py
INSTALLED_APPS = [
...
"rest_framework",
"rest_framework.authtoken",
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.BasicAuthentication',
]
}
- از آنجایی که ما از CKEditor در React استفاده می کنیم، بیایید تنظیمات لازم را برای جلوگیری از خطاهای CORS انجام دهیم.
pip install django-cors-headers
#settings.py
INSTALLED_APPS = [
...,
"corsheaders",
...,
]
MIDDLEWARE = [
...,
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
...,
]
#localhost:5173 my react app url
CSRF_TRUSTED_ORIGINS = ["http://localhost:5173"]
CORS_ORIGIN_WHITELIST = [
"http://localhost:5173",
]
CORS_ORIGIN_ALLOW_ALL = False
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_METHODS = [
"DELETE",
"GET",
"OPTIONS",
"PATCH",
"POST",
"PUT",
]
CORS_ALLOW_HEADERS = [
"accept",
"accept-encoding",
"authorization",
"content-type",
"dnt",
"origin",
"user-agent",
"x-csrftoken",
"x-requested-with",
"token",
]
- حالا بیایید تنظیمات لازم را برای CKEditor انجام دهیم. هم برای عملکرد کاربر و هم برای توسعه دهنده، من می خواستم از CKEditor در خود جنگو استفاده کنم. تنظیماتی که ما در اینجا انجام دادیم برای تعیین مسیر زمانی است که کاربر تصویری را در سمت React آپلود می کند و اطمینان حاصل می کند که جنگو این اجازه را می دهد.
#settings.py
INSTALLED_APPS = [
...,
"ckeditor",
"ckeditor_uploader",
...,
]
CKEDITOR_UPLOAD_PATH = "uploads/"
CKEDITOR_IMAGE_BACKEND = "pillow"
CKEDITOR_STORAGE_BACKEND = 'django.core.files.storage.FileSystemStorage'
CKEDITOR_CONFIGS = {
"default": {
"filebrowserImageUploadUrl": "/ckeditor/upload/",
},
}
#urls.py:
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path("ckeditor/upload/", uploadFile, name="ckeditor_upload"),
path("ckeditor/", include("ckeditor_uploader.urls")),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
ما تنظیمات خود را در جنگو به پایان رساندیم، اکنون به قسمت اصلی یعنی React می رویم.
ابتدا اجازه دهید CKEditor-u را در پروژه خود قرار دهیم.
npm install --save @ckeditor/ckeditor5-react @ckeditor/ckeditor5-build-classic
// AddBlog.jsx
import React, { Component } from 'react';
import { CKEditor } from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
خوب، ما در واقع می توانیم از CKEditor با این استفاده کنیم، اما برای آپلود تصاویر باید تنظیمات بیشتری انجام دهیم.
ابتدا بیایید یک کامپوننت ایجاد کنیم و کدهای لازم را در اینجا بنویسیم.
// components/CustomUploadAdapter.jsx
class CustomUploadAdapter {
constructor(loader) {
this.loader = loader;
this.url="http://127.0.0.1:8000/ckeditor/upload/"; // Here we define the path we specified in django
}
upload() {
return this.loader.file.then(file => new Promise((resolve, reject) => {
const data = new FormData();
data.append('upload', file);
const token = localStorage.getItem('token');
if (!token) {
reject('No token found. User must be logged in to upload images.');
return;
}
fetch(this.url, {
method: 'POST',
body: data,
headers: {
"Authorization": `Token ${token}`
},
})
.then((response) => response.json())
.then(response => {
if (response.url) {
resolve({
default: response.url
});
} else {
reject(response.error ? response.error.message : 'An error occurred while uploading the file.');
}
})
.catch(error => {
reject('An error occurred while uploading the file: ' + error.message);
});
}));
}
abort() {
console.log('Wasted...');
}
}
export default CustomUploadAdapter;
بخش مهمی از این کد که باید به آن توجه کنید استفاده صحیح از توکن کاربر وارد شده و مشخص کردن صحیح آن است. از آنجایی که در سایت من قسمت ورود وجود دارد، این تنظیمات بر اساس آن نوشته شده است.
عالی، اکنون در آخرین قسمت هستیم، اکنون که تمام تنظیمات لازم را انجام داده ایم، می توانیم صفحه AddBlog را به طور کامل ویرایش کنیم.
// AddBlog.jsx
import React, { Component } from 'react';
import { CKEditor } from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import CustomUploadAdapter from '../components/CustomUploadAdapter'; // Let's show the path to the Adapter code we prepared.
const AddBlogs = () => {
const handleChange = (e) => {
const { name, value } = e.target;
setBlogData(prevState => ({
...prevState,
[name]: value
}));
};
const handleCkeditorState = (language, _event, editor) => {
const data = editor.getData();
setBlogData(prevState => ({
...prevState,
[`${language}_content`]: data
}));
};
const handleContentBeforeLoad = (content) => {
const backendBaseURL = 'http://127.0.0.1:8000';
return content.replace(/src="\/media\/(.*?)"/g, `src="${backendBaseURL}/media/$1"`);
};
const onEditorInit = (editor) => {
editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
return new CustomUploadAdapter(loader);
};
};
return (
<div className="addblog">
<h2>{id ? 'Blog Update' : 'Add new blog'}</h2>
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="en_content">En Content:</label>
<CKEditor
editor={ClassicEditor}
data={handleContentBeforeLoad(blogData.en_content)}
onChange={(event, editor) => handleCkeditorState('en', event, editor)}
onReady={onEditorInit}
config={{
extraPlugins: [CustomUploadAdapter],
ckfinder: {
uploadUrl: 'http://127.0.0.1:8000/ckeditor/upload/'
}
}}
/>
</div>
<div className="buttons">
<button id='dashboard__submit__btn' type="submit">{id ? 'Update' : 'Add'}</button>
{id && (
<button id='dashboard__delete__btn' type="button" onClick={handleDelete}><i className="fa-solid fa-trash"></i></button>
)}
</div>
</form>
</div>
);
}
export default AddBlogs;
نتیجه گیری
لازم نیست نگران آن باشید، می توانید به راحتی آن را پیدا کنید و پس از جستجوی دقیق آن را تعمیر کنید. حداکثر، در مورد اینکه کدام نسخه از ابزارها ناسازگار هستند، خطا دریافت خواهید کرد.
قبل از رفتن… اگر سوالی/پیشنهاد/فکری دارید، یک خط زیر را برای من بگذارید. 🖋️
و اگر از این کار لذت بردید، با یک ایموجی زیبا (🤯❤️🔥) به ما بگویید چه احساسی داشتید و فراموش نکنید که برای بهروزرسانیهای بعدی دنبال کنید.
این از من است. به زودی صحبت خواهیم کرد!
– TheHormat ♟️