6
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

django-ckeditorで画像アップロード & カスタマイズ

Last updated at Posted at 2019-12-12

なにをやったのか

完成形

upload.gif

  • django template にWYSIWYGを導入したくて django-ckeditor を入れてみた
  • デフォルトだと画像の埋め込みがURLリンクからしかできなかったので、ローカルストレージからアップロードできるようにした
  • アップロード画面が日本語化されていなかったので自前で上書きして日本語化した
  • 重たい画像をアップロードした時、画面が動かないので動作しているかが不明 -> ローディングイメージを実装

環境など

  • macOS Mojave 10.14.6
  • django-ckeditor 5.8.0

どうやるのか

django-ckeditorまわりの設定

インストールと注意点

  1. リポジトリのREADME にある通りではありますが、普通に pip install django-ckeditor します。
  2. djangoのsettings.py内の INSTALLED_APPSckeditor を追加します。
  3. もしcollectstaticコマンドが実行できる設定がされていなければ、同じくsettings.pyに STATIC_ROOT の記述を加え、 python manage.py collectstatic します。
  4. django-admin以外のTemplateで使用する場合は、Templateに {{ form.media }} を記載する必要があります。下記はその例です。
    (私はこの設定で小一時間ハマりました…)
sample.html
  <h2>ブログ記事登録</h2>
  <form method="POST" enctype="multipart/form-data">
    {{ form.media }}
    {{ form.as_p }}
    {% csrf_token %}
    <button type="submit">登録する</button>
  </form>

upload imageプラグインの適用

  1. djangoのsettings.py内の INSTALLED_APPSckeditor_uploader を追加します。
  2. 同じくsettings.pyに CKEDITOR_UPLOAD_PATH = 'uploads/' など、アップロードした画像を保存するパスを指定します。(これはMEDIA_ROOT配下のディレクトリになります)
  3. 合わせて、画像ファイルのみのアップロードに制限する CKEDITOR_ALLOW_NONIMAGE_FILES = False を指定します。(画像以外もアップロードする場合はこの指定は不要)
  4. CKEDITOR_IMAGE_BACKEND = "pillow" の指定をsettings.pyに記述することで、アップロードした画像のサムネイルを自動で生成してくれ、後に出てくる画像ブラウジングの際にサムネイルが表示されます。
  5. アプリのurlルーティングにckeditor uploaderの設定を追加します。 path('ckeditor/', include('ckeditor_uploader.urls'))

    公式ドキュメントにもありますが、上記5で追加したurlのdecoratorとして @staff_member_required が指定されているため、djangoのデフォルトUsermodelをカスタムしている場合にうまく動かない場合があります。(is_staffカラムを削除している場合など)

    その場合は、 ckeditor_uploader.urls の中身をラップしてしまえばいいので、 公式のソースに倣ってurls.pyを作成し、それをincludeするようにします。

    以下は @staff_member_required の代わりに login_required を使用する例です。
ckedtiror_custom_urls.py
from __future__ import absolute_import

from django.conf.urls import url
from django.contrib.auth.decorators import login_required
from django.views.decorators.cache import never_cache

from ckeditor_uploader import views

urlpatterns = [
    url(r'^upload/', login_required(views.upload), name='ckeditor_upload'),
    url(r'^browse/', never_cache(login_required(views.browse)), name='ckeditor_browse'),
]

ここまでの設定で画像がアップロードできるようになったと思います

自前で日本語化

デフォルトの状態

image.png

デフォルトの状態だと、まず不要なタブが多いですね。
こちらの記事を参考にして、必要最低限のタブだけに絞って日本語も自然に修正しています。

CKEditorをカスタマイズする

ckeditorのconfig.jsという設定関連のソースが static/ckeditor/ckeditor/config.js にありますが、
こちらをそのまま編集すると後々面倒になりそうだったので、個別にjsを作成してそれを対象のtemplate側で読み込むようにしています。

ckeditor_config.js
CKEDITOR.on("dialogDefinition", function (ev) {

// 元記事の記述そのままのため中略

});

これだけだと、 サーバブラウザ を開いたときに以下のように日本語化されていません。
image.png

これを日本語化していきます。

browserのtemplateを上書きする

公式ソースのviews.pyを見ると、 ckeditor/browse.html をレンダリングしていることがわかります。
なので、公式ソースのbrowse.htmlを参考にして、必要な部分を日本語化します。

で、Djangoの適当なApp配下のtemplates内にckeditorのtemplateとして配置します。 (例: blog/templates/ckeditor/browse.html)
そうすることでライブラリのtemplatesではなく、オリジナルのtemplatesが使用されて表示されるようになります。

ローディングイメージを実装

画像をローカルから選択し、アップロードボタンを押すと容量の大きな画像の場合、アップロードに時間がかかり画面がしばらく切り替わらない状態となります。
ユーザーからすると何も動いていないように見えるので、アップロード中だということが分かるようローディングイメージを出そうと思います。

先程作成したckeditor_config.jsを編集し、以下を追加します。

ckeditor_config.js
CKEDITOR.on( 'instanceReady', function(ev){
    const editor = ev.editor;

    editor.on('fileUploadRequest', function(ev){
        const fileLoader = ev.data.fileLoader;
        // Notificationsをbindすることでメインの編集画面に通知が出るが、今回は別Dialogなのであまり意味がない。
        // CKEDITOR.fileTools.bindNotifications(fileLoader.editor, fileLoader);

        fileLoader.on("uploading", function () {
            console.log("アップロード開始");
        });

        fileLoader.on("uploaded", function () {
            console.log("アップロード完了");
        });

        fileLoader.on("error", function () {
            console.log("アップロードエラー");
        });

        fileLoader.on("abort", function () {
            console.log("アップロード失敗");
        });
    });
});

上記では、CKEDITORの instanceReady イベントにhookして、ファイルアップロードWidgetである fileLoader を取得し、
fileLoader に定義されている各イベントごとにリスナーをセットしています。
これらのイベントにhookして、それぞれローディングイメージの表示/非表示を制御してあげればいいです。

さいごに

  • ckeditorは導入自体は楽だけど、カスタマイズしようと思うと本家のソースとかまで読まないといけなくて結構大変。
  • ただ、自前でWYSIWYG作るのはもっと大変なので、それに比べればすごい楽。
  • 繰り返しになりますが、 こちらの記事には本当にお世話になりました。
6
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?