在Django中安装、配置、使用CKEditor5,并将CKEditor5录入的文章展现出来,实现一个简单博客网站的功能

在Django中可以使用CKEditor4和CKEditor5两个版本,分别对应软件包django-ckeditor和django-ckeditor-5。原来使用的是CKEditor4,python manager.py makemigrations时总是提示CKEditor4有安全风险,建议升级到CKEditor5。故卸载了CKEditor4,安装配置CKEditor5,具体步骤如下:

  1. 安装CKEditor5(Debian系统):

    sudo pip3 install django-ckeditor-5

  2. 将"django_ckeditor_5"添加到settings.py的INSTALLED_APPS中:

    INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django_ckeditor_5',
    ......
    ]

  3. 在settings.py中配置CKEditor5(官网标准设置):

    STATIC_URL = '/static/'
    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

    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_CUSTOM_CSS = 'path_to.css' # optional
    CKEDITOR_5_FILE_STORAGE = "path_to_storage.CustomStorage" # optional
    CKEDITOR_5_CONFIGS = {
    'default': {
    'toolbar': ['heading', '|', 'bold', 'italic', 'link',
    'bulletedList', 'numberedList', 'blockQuote', 'imageUpload', ],

    复制代码
     },
     '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',],
         'image': {
             'toolbar': ['imageTextAlternative', '|', 'imageStyle:alignLeft',
                         'imageStyle:alignRight', 'imageStyle:alignCenter', 'imageStyle:side',  '|'],
             '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',
         }
     }

    }

其中定义了三种配置,分别为"default","extends"和"list",下面主要使用"extends"。

  1. 为了使用中文字体,需要修改extends配置,增加fontFamily设置,将中文字体放在英文字体的前面。

    'fontFamily': {
    'options': ['微软雅黑', '宋体', '黑体', '仿宋', '楷体', '隶书', '幼圆', 'Arial', 'Times New Roman', 'Verdana', 'Helvetica', 'Georgia', 'Courier New', 'Impact', 'Comic Sans MS', 'Trebuchet MS'],
    'supportAllValues': 'true',
    },

效果如下:

  1. 为了使用方便,需要设置字体大小,根据word的使用习惯,按字号来设置字体,修改extends配置,增加fontSize设置。

(1) 如果需要下拉列表的字体大小和设置字体大小一样,可以如下设置:

复制代码
    'options': [
    { 'model':'56px', 'title': "初号"},
    { 'model':'48px', 'title': "小初"},
    { 'model':'34.7px', 'title': "一号"},
    { 'model':'32px', 'title': "小一"},
    { 'model':'29.3px', 'title': "二号"},
    { 'model':'24px', 'title': "小二"},
    { 'model':'21.3px', 'title': "三号"},
    { 'model':'20px', 'title': "小三"},
    { 'model':'18.7px', 'title': "四号"},
    { 'model':'16px', 'title': "小四"},
    { 'model':'14px', 'title': "五号"},
    { 'model':'12px', 'title': "小五"},
    { 'model':'10px', 'title': "六号"},
    { 'model':'8.7px', 'title': "小六"},
    { 'model':'7.3px', 'title': "七号"},
    { 'model':'6.7px', 'title': "八号"},
    ],
    'supportAllValues': 'true',
   },

效果如下:

(2) 如果不需要下拉列表的字体大小和实际字体大小一样,可以增加显示格式设置,将下拉列表字体大小都统一为14px:

复制代码
  'fontSize': {
    'options': [
    { 'model':'56px', 'title': "初号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'48px', 'title': "小初", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'34.7px', 'title': "一号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'32px', 'title': "小一", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'29.3px', 'title': "二号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'24px', 'title': "小二", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'21.3px', 'title': "三号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'20px', 'title': "小三", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'18.7px', 'title': "四号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'16px', 'title': "小四", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'14px', 'title': "五号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'12px', 'title': "小五", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'10px', 'title': "六号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'8.7px', 'title': "小六", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'7.3px', 'title': "七号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'6.7px', 'title': "八号", 'view': {'styles': { "font-size": '14px' }}},
    ],
    'supportAllValues': 'true',
   },

效果如下:

我个人使用了第二种,另外加上一些常规设置,settings.py中CKEditor5的全部设置如下:

复制代码
STATIC_ROOT = os.path.join(BASE_DIR,"static/")
MEDIA_URL = "media/"
MEDIA_ROOT = os.path.join(BASE_DIR,"media/")

CKEDITOR_5_CONFIGS = {
'default': {
  'toolbar': ['heading', '|', 'bold', 'italic', 'link',
           'bulletedList', 'numberedList', 'blockQuote', 'imageUpload', ],
},
'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',],
  'image': {
     'toolbar': ['imageTextAlternative', '|', 'imageStyle:alignLeft',
              'imageStyle:alignRight', 'imageStyle:alignCenter', 'imageStyle:side',  '|'],
     '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' }
     ]
  },

  'fontFamily': {
        'options': ['微软雅黑', '宋体', '黑体', '仿宋', '楷体', '隶书', '幼圆', 'Arial', 'Times New Roman', 'Verdana', 'Helvetica', 'Georgia', 'Courier New', 'Impact', 'Comic Sans MS', 'Trebuchet MS'],
        'supportAllValues': 'true',
    },
  'fontSize': {
    'options': [
    { 'model':'56px', 'title': "初号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'48px', 'title': "小初", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'34.7px', 'title': "一号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'32px', 'title': "小一", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'29.3px', 'title': "二号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'24px', 'title': "小二", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'21.3px', 'title': "三号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'20px', 'title': "小三", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'18.7px', 'title': "四号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'16px', 'title': "小四", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'14px', 'title': "五号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'12px', 'title': "小五", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'10px', 'title': "六号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'8.7px', 'title': "小六", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'7.3px', 'title': "七号", 'view': {'styles': { "font-size": '14px' }}},
    { 'model':'6.7px', 'title': "八号", 'view': {'styles': { "font-size": '14px' }}},
    ],
    'supportAllValues': 'true',
   },
   'height': '800px',
},
'list': {
  'properties': {
     'styles': 'true',
     'startIndex': 'true',
     'reversed': 'true',
  }
}
}

# Define a constant in settings.py to specify file upload permissions
CKEDITOR_5_FILE_UPLOAD_PERMISSION = "authenticated"  # Possible values: "staff", "authenticated", "any"

CKEDITOR_5_USER_LANGUAGE=True #使用Django配置的语言

6.修改项目的urls.py,如下所示:

复制代码
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/login/', sign_in, name='admin_login'),  #替代admin原始登录界面
    path('admin/', admin.site.urls),
    ......
]

urlpatterns += [
path("ckeditor5/", include('django_ckeditor_5.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  1. 在项目应用(假设为myapp)的models.py中新建CKEditor类:

    from django.db import models
    from django_ckeditor_5.fields import CKEditor5Field

    class CkeditorArt(models.Model):
    #content = models.TextField(verbose_name='内容')
    article_id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=200,verbose_name='标题',default='CKEditor编辑页面')
    content = CKEditor5Field('内容',config_name='extends')

    复制代码
     #定义模型在admin管理界面显示名称,也可在admin.py中新建ModelAdmin类使用list_display来设置
     def __str__(self):
         return f"{self.title},{self.content}"
  2. 在项目应用(myapp)的forms.py中新建表单类:

    from django import forms
    from django_ckeditor_5.widgets import CKEditor5Widget
    from .models import CkeditorArt

    class PostAdminForm(forms.ModelForm):
    def init(self, *args, **kwargs):
    super().init(*args, **kwargs)
    self.fields["content"].required = False

    复制代码
     title = forms.CharField(label='文章标题',max_length=200, required=True, widget=forms.TextInput(attrs={"placeholder": "在这里输入标题",'style': 'width: 500px;'}),)
     class Meta:
         model = CkeditorArt
         fields = ('title','content')
         widgets = {
         "content": CKEditor5Widget(
             attrs={"class": "django_ckeditor_5"}, config_name="extends"
         )
     }

此处的CKEditor的配置config_name为前面setttings.py中设置extends配置。

  1. 为便于使用Django后台管理CKEditor表单提交的内容,在项目应用(myapp)的admin.py中增加如下内容:

    from .models import CkeditorArt
    class CkeditorArtAdmin(admin.ModelAdmin):
    list_display = ('title','content')
    admin.site.register(CkeditorArt,CkeditorArtAdmin)

  2. 更新数据库和static文件

    python3 manage.py makemigrations
    python3 manage.py migrate
    python3 manage.py collectstatic

  3. 在项目应用(myapp)的urls.py中设置路径:

    from django.urls import path
    from . import views

    urlpatterns = [
    path('Ckeditor/', views.Ckeditor, name='ckeditor'),
    .....
    ]

12.在项目应用(myapp)的views.py中新建上面提到的view函数Ckeditor:

复制代码
from django.shortcuts import render
from django.http import HttpResponse
from .forms import PostAdminForm

@login_required(login_url='/login/')  #需要登录用户权限
def Ckeditor(request):
    """ 自定义form表单 """
    if request.method == 'POST':
        form = PostAdminForm(data=request.POST)
        if form.is_valid():
            form.save()
            return render(request, 'form-post-finished.html')
    form = PostAdminForm()
    return render(request, 'ckeditor-form.html', {'form':form})

13.在项目应用(myapp)的templates目录下新建上面提到的ckeditor-form.html,主要内容如下:

复制代码
{% extends "newdesign/newbase.html" %}

    {% block mytitle %}  
        <title>Ckeditor富文本编辑</title>
    {% endblock %}

    {% block maincontent %}
    <div class="row">
        <form method="post", class="form-horizontal">
            {% csrf_token %}
          <p>标题: {{form.title |safe}}</p>
          <p>文章内容:</p> 
            {{form.content |safe}}
            {{form.media}}
            <input type="submit" value="Submit">
        </form>
    </div>       
    {% endblock %}

通过地址/myapp/Ckeditor即可访问CKEditor编辑页面,可以直接把word排版好的内容拷贝过来,格式和照片等都可以按word的排版正常显示。

  1. 在CKEditor表单页面输入文章标题,完成文章内容,示例如下,然后submit提交。

提交后可以在Django的管理后台看到相关记录:

15. 下面将所有文章以列表的形式在网页上展示出来,点击列表中文章的标题,即可展示文章内容,效果如下:

(1)在项目应用(myapp)的urls.py中设置bloglist和每篇文章的路径:

复制代码
from django.urls import path
from . import views


urlpatterns = [
    path('Ckeditor/', views.Ckeditor, name='ckeditor'),
    path('bloglist/', views.Bloglist, name='bloglist'),   
    path('blog/<str:article_id>/', views.Showblog, name='showblog'),   
]

(2)在项目应用(myapp)的views.py中新建上面提到的view函数Bloglist和Showblog:

复制代码
from .models import CkeditorArt
#@login_required(login_url='/login/')
def Showblog(request,article_id):
    try:
        article = CkeditorArt.objects.get(article_id=article_id)
        return render(request, 'showblog.html', {'content':article.content,'title':article.title})
    except CkeditorArt.DoesNotExist:
        message = '<h1 style="color: red;">文章没找到!<h1>'
        return render(request, 'showblog.html', {'content':message,'title':'文章没找到'})


#@login_required(login_url='/login/')
def Bloglist(request):
    #values返回字典,values_list返回元组
    objs = CkeditorArt.objects.values('article_id','title')
    context = {
    'objs':objs,
    }
    return render(request,'bloglist.html', context) 

(3)在项目应用(myapp)的templates目录下新建上面提到的bloglist.html和showblog.html

bloglist.html

复制代码
{% extends "newdesign/newbase.html" %}

        {% block mytitle %}
            <title>BLOG列表</title>
        {% endblock %}

       {% block maincontent %}  
        <h1>这是CkEditor编辑的BLOG清单</h1>
        <div>
            <ul>
                {% for obj in objs %}
                <h5>文章{{obj.article_id}}: <a href="/myapp/blog/{{ obj.article_id }}/">{{obj.title}}</a></h5>
                {% endfor %}
            </ul>
        </div>
    {% endblock %}

showblog.html

复制代码
{% extends "newdesign/newbase.html" %}

    {% block mytitle %}  
        <title>{{title}}</title>
    {% endblock %}

    {% block maincontent %}

    <h2>{{title}}</h2>

    {{content|safe}}
    {% endblock %}

至此,通过CKEditor就基本实现了一个简单博客网站的功能。

相关推荐
不光头强4 小时前
Spring框架的事务管理
数据库·spring·oracle
百***92027 小时前
【MySQL】MySQL库的操作
android·数据库·mysql
q***76667 小时前
Spring Boot 从 2.7.x 升级到 3.3注意事项
数据库·hive·spring boot
信仰_2739932437 小时前
Redis红锁
数据库·redis·缓存
人间打气筒(Ada)7 小时前
Centos7 搭建hadoop2.7.2、hbase伪分布式集群
数据库·分布式·hbase
心灵宝贝7 小时前
如何在 Mac 上安装 MySQL 8.0.20.dmg(从下载到使用全流程)
数据库·mysql·macos
奋斗的牛马8 小时前
OFDM理解
网络·数据库·单片机·嵌入式硬件·fpga开发·信息与通信
忧郁的橙子.9 小时前
一、Rabbit MQ 初级
服务器·网络·数据库
杰杰7989 小时前
SQL 实战:用户访问 → 下单 → 支付全流程转化率分析
数据库·sql