Wagtailのすすめ(1) DjangoベースのCMSを比較・検討してWagtailを選択した話

# はじめに

何年か前に，webインタラクションやシリアスゲーム実験などのために自前のサイトがあれば便利だなと思いたち，ベースとなるCMSについての情報収集を始めた．ラボにはDjangoが根付いてきていたので，条件は，DjangoベースのCMSであること，そして，他の自作のDjangoアプリとの連携が容易なことである．

少し調べてみて，すぐに，Djangoベースの主なCMSは，

- [Django-CMS](https://www.django-cms.org/en/)
- [Mezzanine](http://mezzanine.jupo.org/)
- [Wagtail](https://wagtail.io/)

の3つであることがわかった．

Django-CMSは，CMSとしての完成度は高そうだけど，細かなカスタマイズが難しそうだったため最初に候補から外れた．Mezzanineは，WordPressと似ていて馴染みやすく，機能も充実しており，ある程度カスタマイズもできそうだった．それで，Mezzanineを選ぼうかとも考えたんだけど，Wagtailを触ってみて，その柔軟性の高さに驚き，すぐにそちらに心変わりした．

目的や嗜好によってどれが適しているかは変わると思うけれど，少なくとも自分にはWagtailがぴったりだった（ので，是非オススメしたい）．本稿では，自分のための備忘録も兼ねて，Wagtailの基礎知識を整理しておこうと思う．

# Wagtailとは

WagtailはDjangoベースのCMSライブラリの1つで，サイトを構築するために自分で書かなければならないコードは他の類似のライブラリと比べると多くなるが，その分，Djangoとのつながりがわかりやすく，カスタマイズしやすいという特長がある．

一方，ライブラリを利用せずに，純粋にDjangoのみでサイトを構築する場合と比べると，Wagtailを上にかぶせるメリットとして，すぐに思いつくものだけでも，次のような点が挙げられる．

- Wagtailの管理サイトでウェブページのコンテンツを編集できる
- その際に，リッチテキストエディタが利用できる
- 下書き，公開など，ページの状態を管理できる
- ページがツリー構造に整理されており，それに沿ってurlルーティングが自動的に行われる（標準的な使い方ではurls.pyの編集は不要）
- ページはview関数を介さずにテンプレートに対応付けられている（標準的な使い方ではviews.pyの編集は不要）
- Wagtailの管理サイトで画像も簡単に管理できる
- 画像をページに含める際のサイズ調整などのちょっとした操作がテンプレートタグだけで処理できる


# はじめの一歩

[公式ドキュメント](https://docs.wagtail.io/en/stable/)の説明に従ってWagtailをインストールしたとする．サイトを構築するには，最初に次のコマンドを打ち込む．

```console
$ mkdir myWagtail
$ cd myWagtail
$ wagtail start config .
```

3行目のコマンドは，

```console
$ django-admin.py startproject config .
```

を拡張したものである．これによって，myWagtailディレクトリの中にconfigという名称のDjangoのプロジェクトが作成され，homeとsearchという2つのアプリケーションがデフォルトで追加される．また，settingsはファイル（pythonモジュール）からディレクトリ（pythonパッケージ）に変更される．

続いて，自作のページを定義していくために，それ用のアプリケーションを追加する．アプリケーションの追加の仕方は素のDjangoと同じである（cmsはアプリケーションの名称）．

```console
$ python manage.py startapp cms
```

この段階で，ディレクトリ構成は次のようになる．

```
myWagtail/
    manage.py
    cms/
        __init__.py
        admin.py
        apps.py
        models.py
        tests.py
        views.py
        migrations/
            __init__.py
    config/
        __init__.py
        urls.py
        wsgi.py
        settings/
            __init__.py
            base.py
            dev.py
            production.py
        static/
            css/
                config.css
            js/
                config.js
        templates/
            404.html
            500.html
            base.html
    home/
        __init__.py
        models.py
        migrations/
            __init__.py
        static/
            css/
                welcome_page.css
        templates/
            home/
                home_page.html
                welcome_page.html
    search/
        __init__.py
        views.py
        templates/
            search/
                search.html
```

この段階でDjangoの開発用サーバを

```console
$ python manage.py runserver
```

で立ち上げて，

http://localhost:8000/

にアクセスすると，簡単なWelcomeページが表示される．このページはどこから来たのだろう．

config/urls.pyをみてみると，urlルーティングは，

```python
from django.urls import include, path
from django.contrib import admin
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.core import urls as wagtail_urls
from wagtail.documents import urls as wagtaildocs_urls
from search import views as search_views

urlpatterns = [
    path('django-admin/', admin.site.urls),
    path('admin/', include(wagtailadmin_urls)),
    path('documents/', include(wagtaildocs_urls)),
    path('search/', search_views.search, name='search'),
]

urlpatterns = urlpatterns + [
    path("", include(wagtail_urls)),
]
```

のようになっている．上から順にみていくと，djangoの管理サイトはdjango-admin/に割り当てられており，admin/にはWagtailの方の管理サイトが対応付けられていることがわかる．documents/は，pdfファイルなどのドキュメントをサーブするためにWagtailが利用するアドレスであり，search/には，searchアプリケーションのview関数`search()`が割り当てられている（このview関数は，search/views.pyの中に定義されている）．

それら以外のアドレスはすべて`include(wagtail_urls)`で処理されている．ここでのルーティングは，基本的には，これから作成していくページ間のツリー構造に従って決められていく．初期状態では，home/models.pyにある`HomePage`クラスのインスタンス（ページ）が1つだけ作成されており，上ではそのページが表示された．

この際に利用されたテンプレートが，home/templates/home/home_page.htmlである．例えば，このファイルを次のように書き換えてみると，それが確かめられる．

```html
{% extends "base.html" %}

{% block content %}
    <h1>Hello World!</h1>
{% endblock %}
```

なお，1行目は，このテンプレートがbase.htmlを拡張したものであることを示している．このbase.htmlは，config/templatesの中にあるので，確認しておこう．

`HomePage`はサイト全体の表紙ページのためのクラスである．home/models.pyをみればわかるように，現時点では，デフォルトのPageモデルから何ら拡張されていないが，実際にサイトを構築するときには必要に応じて拡張していくことになる．また，対応するテンプレートもあわせて修正していく．

表紙ページ以外のページのためのクラスは，通常，別のアプリケーションの中で定義していく．上の例では，cmsアプリケーションがそれにあたる．

実際のページ（ページクラスのインスタンス）の生成や，そのコンテンツの編集，ページ間のツリー構造の定義などは，Wagtailの管理サイトで行う．純粋なDjangoの場合，管理サイトの構成（何を編集できるようにするか）はcms/admin.pyなどの中で指定していたが，Wagtailの管理サイトの構成はcms/models.pyでページクラスを定義するときにあわせて指定する．

```console
$ python manage.py createsuperuser
```

で管理者アカウントを作成して，

```console
http://localhost:8000/admin/
```

でWagtailの管理サイトの感触を確認してみてほしい．

# おわりに

今回は，DjangoベースのCMSライブラリ，Wagtailのはじめの一歩について紹介した．実際にサイトを構築するためにはまだ情報が不十分だと思うが，次回以降の記事で少しずつ補足していきたい．

さっと一通りイメージをつかみたい場合は，公式サイトの[Your first Wagtail site](https://docs.wagtail.io/en/stable/getting_started/tutorial.html)を作ってみるといいだろう．発展的な話題については，[ここのチュートリアル](https://www.accordbox.com/blog/wagtail-tutorials/)がわかりやすいと思う．

# リンク

- [Wagtailのすすめ(2) ページを定義し，編集し，表示してみよう](https://qiita.com/j54854/items/3dcc7f6ddf54daf1a6b6)
- [Wagtailのすすめ(3) ページのツリー構造を理解し，利用しよう](https://qiita.com/j54854/items/f8c2cd6fb02bbc36a43d)
- [Wagtailのすすめ(4) テンプレートにコンテキストを渡そう](https://qiita.com/j54854/items/c5ae6b0d6e3520af8999)
- [Wagtailのすすめ(5) StreamFieldに独自ブロックを追加しよう](https://qiita.com/j54854/items/7e51a5f485c41d9c22ae)
- [Wagtailのすすめ(6) カテゴリとタグを追加しよう](https://qiita.com/j54854/items/111fb99eadfac6a26c29)