小火车 2019-07-01
前面我们已经实现了用Markdown语法写文章了。但是文章的评论用Markdown就不太合适了,你不能强求用户也花时间去熟悉语法啊。另外评论中通常还有表情、带颜色的字体等功能,这些也是Markdown不具备的。
因此富文本编辑器Django-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']), } }
这样就完成了:
代码高亮效果不错!
为了让用户在前台也能使用富文本编辑器,还得对代码稍加改动。
首先需要把评论的表单传递到文章详情页面中。因此修改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,多平台发稿很方便。
感谢Aaron Zhao 的个人博客提供了本文的参考。博主还讲解了django-ckeditor上传图片的设置,有兴趣可以前往了解。
$oFCKeditor->Value = 'This is some <strong>sample text</strong>' ;<textarea name="content" style=&qu