Django搭建個人部落格:使用django-ckeditor富文字編輯器

杜賽_dusai發表於2019-03-21

前面我們已經實現了用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了:

img

功能相當齊全,字型、字號、顏色、連結、表情應有盡有。

如果我只需要部分功能怎麼辦呢?比如插入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中指定使用。效果如下:

img

編輯富文字搞定後,還需要在前臺介面中展示出來。富文字是以類似html的格式進行儲存的,因此還要在展示評論的程式碼加入|safe過濾器,防止瀏覽器進行轉義。

修改detail.html中展示評論的部分程式碼:

templates/article/detail.html

...

<!-- 顯示評論 -->
<h4>共有{{ comments.count }}條評論</h4>
<div>
    {% for comment in comments %}
        ...
        <!-- 修改這裡 -->
        <div>{{ comment.body|safe }}</div>
    {% endfor %}
</div>

...
複製程式碼

進入文章詳情頁面看看效果:

img

程式碼高亮

程式碼高亮需要新增額外的外掛Prism。在Prism外掛官方頁面下載(也可以點選這裡直接下載)後,將解壓出來的prism放到env\Lib\site-packages\ckeditor\static\ckeditor\ckeditor\plugins目錄下。注意env是你建立的虛擬環境的目錄。

之前你安裝的所有庫都在這個env目錄中的。

然後在Prism官網選擇主題:

img

  • 根據喜好選擇一個喜歡的主題
  • 然後選擇需要高亮的語言。不清楚就可以全選
  • 勾選行號外掛
  • 最後點選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' %}">

...
複製程式碼

Prismwidgetlineutils外掛新增到配置檔案中。後面兩個編輯器自帶,不用單獨下載,添上就可以了:

my_blog/settings.py

...
CKEDITOR_CONFIGS = {
    'default': {
        ...
        # 新增 Prism 相關外掛
        'extraPlugins': ','.join(['codesnippet', 'prism', 'widget', 'lineutils']),
    }
}
複製程式碼

這樣就完成了:

img

程式碼高亮效果不錯!

在前臺使用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則是評論正文欄位。

看看效果:

img

不錯,編輯器已經可以正常使用了,但還有一個小問題:似乎編輯器寬度沒有自適應,右邊大片白白的空間也太浪費了。繼續努力。

寬度自適應

首先在配置檔案中將寬度設定為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程式碼都採取這種方法插入。

重新整理頁面,編輯器就能夠寬度自適應了:

img

發表含有程式碼塊的評論,詳情頁面的顯示如下:

img

總結

現在,博文和其評論都可以漂亮的排版了。對於有些不喜歡Markdown的人來說,甚至可以連博文都使用django-cdeditor提供的富文字編輯器。我自己還是傾向用Markdown寫文章:寫作效率比好看更重要,並且主流網站幾乎都支援Markdown,多平臺發稿很方便。

感謝Aaron Zhao 的個人部落格提供了本文的參考。博主還講解了django-ckeditor上傳圖片的設定,有興趣可以前往瞭解。

相關文章