前面我们已经实现了用 Markdown 语法写文章了。但是文章的评论用 Markdown 就不太合适了,你不能强求用户也花时间去熟悉语法啊。另外评论中通常还有表情、带颜色的字体等功能,这些也是 Markdown 不具备的。
因此富文本编辑器 Django-ckeditor 就派上用场了。
在后台使用 Ckeditor
在虚拟环境中安装 django-ckeditor:
(env) > pip install django-ckeditor
安装成功后还是老规矩,在 settings.py 中注册 app:
my_blog/settings.py
…
INSTALLED_APPS = [
…
‘ckeditor’,
…
]
…
接下来需要修改模型了。用 django-ckeditor 库自己的富文本字段 RichTextField 替换普通的文本字段 TextField:
comment/models.py
…
# django-ckeditor
from ckeditor.fields import RichTextField
class Comment(models.Model):
…
# 之前为 body = models.TextField()
body = RichTextField()
…
记得每次修改模型后要迁移数据:
(env) > python manage.py makemigrations
(env) > python manage.py migrate
为方便测试,修改 comment/admin.py 文件,将评论模块注册到后台中:
comment/admin.py
from django.contrib import admin
from .models import Comment
admin.site.register(Comment)
启动服务器,进入后台的评论页面,发现已经可以使用 django-ckeditor 了:
功能相当齐全,字体、字号、颜色、链接、表情应有尽有。
如果我只需要部分功能怎么办呢?比如插入 flash 动画基本就用不到。另外似乎也没看到插入代码块的功能。
ckeditor 允许你在 settings.py 中进行自定义配置:
my_blog/settings.py
…
CKEDITOR_CONFIGS = {
# django-ckeditor 默认使用 default 配置
‘default’: {
# 编辑器宽度自适应
‘width’:’auto’,
‘height’:’250px’,
# tab 键转换空格数
‘tabSpaces’: 4,
# 工具栏风格
‘toolbar’: ‘Custom’,
# 工具栏按钮
‘toolbar_Custom’: [
# 表情 代码块
[‘Smiley’, ‘CodeSnippet’],
# 字体风格
[‘Bold’, ‘Italic’, ‘Underline’, ‘RemoveFormat’, ‘Blockquote’],
# 字体颜色
[‘TextColor’, ‘BGColor’],
# 链接
[‘Link’, ‘Unlink’],
# 列表
[‘NumberedList’, ‘BulletedList’],
# 最大化
[‘Maximize’]
],
# 加入代码块插件
‘extraPlugins’: ‘,’.join([‘codesnippet’]),
}
}
在 toolbar_Custom 中定义需要使用的功能模块;没列出的功能就不再显示了。代码块功能是编辑器自带的插件,需要在 extraPlugins 中指定使用。效果如下:
编辑富文本搞定后,还需要在前台界面中展示出来。富文本是以类似 html 的格式进行保存的,因此还要在展示评论的代码加入 |safe 过滤器,防止浏览器进行转义。
修改 detail.html 中展示评论的部分代码:
templates/article/detail.html
…
<!– 显示评论 –>
<h4> 共有 {{comments.count}} 条评论 </h4>
<div>
{% for comment in comments %}
…
<!– 修改这里 –>
<div>{{comment.body|safe}}</div>
{% endfor %}
</div>
…
进入文章详情页面看看效果:
代码高亮
代码高亮需要添加额外的插件 Prism。在 Prism 插件官方页面下载(也可以点击这里直接下载)后,将解压出来的 prism 放到 env\Lib\site-packages\ckeditor\static\ckeditor\ckeditor\plugins 目录下。注意 env 是你创建的虚拟环境的目录。
之前你安装的所有库都在这个 env 目录中的。
然后在 Prism 官网选择主题:
根据喜好选择一个喜欢的主题
然后选择需要高亮的语言。不清楚就可以全选
勾选行号插件
最后点击 DOWNLOAD CSS 下载样式
在 static 目录中新建 prism 目录,将下载好的 CSS 文件放进去。
注意这里的 static 是项目中的静态文件目录(与前面的章节相同),而不是 env 文件夹中的 static 目录。
然后在需要代码高亮的模板文件中引用 prism 的静态文件,对代码进行渲染:
templates/article/detail.html
…
<script src=”{% static ‘ckeditor/ckeditor/plugins/prism/lib/prism/prism_patched.min.js’ %}”></script>
<link rel=”stylesheet” href=”{% static ‘prism/prism.css’ %}”>
…
将 Prism、widget、lineutils 插件添加到配置文件中。后面两个编辑器自带,不用单独下载,添上就可以了:
my_blog/settings.py
…
CKEDITOR_CONFIGS = {
‘default’: {
…
# 添加 Prism 相关插件
‘extraPlugins’: ‘,’.join([‘codesnippet’, ‘prism’, ‘widget’, ‘lineutils’]),
}
}
这样就完成了:
代码高亮效果不错!
在前台使用 Ckeditor
为了让用户在前台也能使用富文本编辑器,还得对代码稍加改动。
首先需要把评论的表单传递到文章详情页面中。因此修改 article_detail 视图:
article/views.py
…
# 引入评论表单
from comment.forms import CommentForm
…
# 文章详情
def article_detail(request, id):
…
# 引入评论表单
comment_form = CommentForm()
context = {
…
‘comment_form’: comment_form,
}
…
然后将 detail.html 原来评论表单中的正文部分(即前面章节写的 <textarea>)替换如下:
templates/article/detail.html
…
<!– 发表评论 –>
<form …>
{% csrf_token %}
<div class=”form-group”>
<label for=”body”>…</label>
<!– 将之前的 <textarea> 替换掉 –>
<!– <textarea type=”text”
class=”form-control”
id=”body”
name=”body”
rows=”2″></textarea> –>
<div>
{{comment_form.media}}
{{comment_form.body}}
</div>
</div>
<!– 提交按钮 –>
…
</form>
…
其中的 comment_form.media 是编辑器自身的渲染代码,comment_form.body 则是评论正文字段。
看看效果:
不错,编辑器已经可以正常使用了,但还有一个小问题:似乎编辑器宽度没有自适应,右边大片白白的空间也太浪费了。继续努力。
宽度自适应
首先在配置文件中将宽度设置为 auto,这一步我们已经做好了。
Ckeditor 编辑器本身有一个 inline-block 的样式,阻碍了自适应效果,需要用 Jquery 语法将其清除掉。在详情页面底部加入代码:
templates/article/detail.html
<!– 注意这是错误的示范!–>
…
<!– 新增代码 –>
<script>
$(“.django-ckeditor-widget”).removeAttr(‘style’);
</script>
<!– 这个已经有了 –>
{% endblock content %}
$ 符号代表 Jquery 语句。这句的意思是:找到页面中 class=’django-ckeditor-widget’ 的容器,然后删除这个容器的 style 属性。
看似没什么问题,然而 Bug 藏在细节中。注意这是个 Jquery 语句,那么就要求运行之前先载入 Jquery.js。然而在渲染页面时,包含 $ 语句的 {% block content %} 会插入到 base.html 模板的 Jquery.js 标签的前面,导致语句不会生效,并且控制台会报出 $ is not defined 的错误。
比较容易想到的办法是将引入 Jquery.js 的标签提到更顶部的位置,在 block 模板插入前就加载。这样做的问题是 JS 文件加载通常较慢,它会阻塞后面的代码,从而减缓页面整体加载速度。本文不采用这种办法。
解决方案是在 base.html 中新增专门用于拼接 JavaScript 脚本的位置,命名为{% block script %}。注意它必须放置在 Jquery 标签的后面:
templates/base.html
…
<body>
…
<!– 已有代码 –>
<script src=”{% static ‘jquery/jquery-3.3.1.js’ %}”></script>
…
<!– 新增代码 –>
{% block script %}{% endblock script %}
</body>
然后将 detail.html 中的 JS 代码放到这个块中:
templates/article/detail.html
…
{% block script %}
<script>
$(“.django-ckeditor-widget”).removeAttr(‘style’);
</script>
{% endblock script %}
这种方法可以灵活的定义 JS 脚本的运行顺序,并且代码看起来更加整洁。推荐所有的 JS 代码都采取这种方法插入。
刷新页面,编辑器就能够宽度自适应了:
发表含有代码块的评论,详情页面的显示如下:
总结
现在,博文和其评论都可以漂亮的排版了。对于有些不喜欢 Markdown 的人来说,甚至可以连博文都使用 django-cdeditor 提供的富文本编辑器。我自己还是倾向用 Markdown 写文章:写作效率比好看更重要,并且主流网站几乎都支持 Markdown,多平台发稿很方便。
有疑问请在杜赛的个人网站留言,我会尽快回复。
或 Email 私信我:dusaiphoto@foxmail.com
项目完整代码:Django_blog_tutorial
感谢 Aaron Zhao 的个人博客提供了本文的参考。博主还讲解了 django-ckeditor 上传图片的设置,有兴趣可以前往了解。