Django + Wagtail + Puput + CodeRedCMS + markdownのGit分散型ノベルアプリケーションをつくる

## 前回までのあらすじ

Djangoアプリも社内でつくりはじめたコンテナ初心者、CMSとしてDjangoにwagtailの搭載に成功。これを使ってGitによる分散型CMSアプリケーションをつくりはじめる。

[Qiita: Django + Wagtail + Puputの小説アプリケーションのベース作成 https://qiita.com/GCkurabe/items/fd753a6951199bcaf12e](https://qiita.com/GCkurabe/items/fd753a6951199bcaf12e)

## 今回の内容
今回は前回のリポジトリのファイル群であるwagtail+puputを使用してCMSアプリケーションを作ってみようと思います。画像などはいまも載せられるので文章周りやデザインの改良をやって、小説などを書きやすくしていきます。

具体的にはまずコンテンツを書くためにmarkdownをpuput内部で使えるようにプラグインをカスタマイズします。

こんな感じで使えます。


<img width="1437" alt="スクリーンショット 2019-10-20 17.40.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431414/da5c3372-6251-145a-adc2-bbb318321a16.png">

<img width="1444" alt="スクリーンショット 2019-10-20 17.41.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431414/fa5611b6-82df-c5fd-78fd-739ce7bcef64.png">


markdownはqiitaやwikiなどでよく使われるもので、小説などで使われる事例はまだ多くはありません。しかし非常に移植が行いやすく、いかなるwebサイトでも同じ見た目を表現できます。またgitでの管理も非常に行いやすいので、それぞれのリポジトリで小説をmarkdownで管理し、小説の編集をより簡易に行えるようにしていけるのではないかと考えています。なによりも、wordの煩わしさからも解放され、Atomで全てを記入できるようになるのでかなりいいのではないかと思います。とAtom信者の私は考えています。

これを最終的に、Git分散型ノベルアプリケーション(Distributed-Novel-Application-by-Git)とすることで、ノベルアプリケーションを作る人たちが各々でpuputやwagtail,djangoやpostgreSQL,docker-composeをカスタマイズしてみんなが見れる個人サイト運営とかまでできればいいなと思ってます。今はまだプログラマー寄りな実装になってしまいますが、いずれはエンドユーザーにとって使いやすくカスタマイズも行いやすいwebアプリとしてリリースできるようにしていきたいと思っています。

また、wagtailに関して調べ回っている時、以下の記事をみて大変面白そうだと興味を惹かれました。

[nginx+Django+CodeRedCMSを立てた件 備忘録: https://qiita.com/sekirei/items/6f7dfdaabecec984883a](https://qiita.com/sekirei/items/6f7dfdaabecec984883a)

公式サイトをみてみると結構いろいろすでに組み込んであります。かなり便利そうです。

[CODERED: https://www.coderedcorp.com/cms/](https://www.coderedcorp.com/cms/)

というわけでこのCodeRedCMSの組み込みも同時に行っていきます。

## GitHubリポジトリ

GitHubにコミットをかけておきました。ここからpullしてくれば簡単にCodeRedCMSにmarkdownを使えるようにしたpuputを試すことができます。docker-composeでの実装のいいところはこういうのを簡単に共有できるところにあります。

[Distributed-Novel-Application-by-Git: https://github.com/kurawo/Distributed-Novel-Application-by-Git](https://github.com/kurawo/Distributed-Novel-Application-by-Git)

ただ例のごとく本番環境で運用できる状態にしてはいないので、個人の閉鎖環境のdocker用マシンで試していただければと思います。

## puputのコードを編集できるようにするためのdocker cp
puputはプラグインという背景もあり、いままでのdjangoアプリと異なり全く違うディレクトリにファイルが配置されています。これを編集しないと、markdownを導入することができません。このため、これをdocker-composeが読み込み、dockerVMとdockerCtrがファイルを共有できるように再度設定を行う必要があります。

とはいえ、まずコンテナ上からデータを引っ張ってこなければなりません。そこで、以下のコマンドを実行してコンテナからVMにデータを引っ張ってきます。

まずdocker psでdjangoのCONTAINER IDを確認し、その後CONTAINER IDをもとにしてpuputのディレクトリへアクセスし、「./」つまり現在のディレクトリへコピーしてきます。

[参考 Docker cp使って簡単永続化:https://qiita.com/Nedward/items/d64749f447c9e11f411c](https://qiita.com/Nedward/items/d64749f447c9e11f411c)

```
# docker ps
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS              PORTS                    NAMES
a4f2a76aaaae        nginx                         "nginx -g 'daemon of…"   7 minutes ago       Up 7 minutes        0.0.0.0:80->80/tcp       docker-django-master_nginx_1
6689c93aaaad        docker-django-master_django   "bash -c 'cd mysite …"   7 minutes ago       Up 7 minutes        3031/tcp                 docker-django-master_django_1
1c7d719aaaa1        postgres                      "docker-entrypoint.s…"   7 minutes ago       Up 7 minutes        0.0.0.0:5432->5432/tcp   docker-django-master_postgres_1
# docker cp 6689c93aaaad:/usr/local/lib/python3.7/site-packages/puput ./
```

これが終わったら、docker-compose.ymlを編集してpuputディレクトリでのVMとCtrでの変更を同期できるようにします。

```
version: '3.7'
services:
  django:
  #中略
  volumes:
    - "./mysite/static:/opt/apps/mysite/static"
    - "./django:/opt/apps" # 2019/09/28 kurawo add
    - "./puput:/usr/local/lib/python3.7/site-packages/puput" # 2019/10/19 kurawo add
    #以下省略
```

これでpuputの編集を行う準備ができました。

## markdownを使えるようにする

以下の記事を参考にmarkdownを投入してみます。

[wagtail markdown field を使ってみる: https://www.monotalk.xyz/blog/wagtail-markdown-field-%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B/](https://www.monotalk.xyz/blog/wagtail-markdown-field-%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B/)

[rago1975が自ら環境を構築して執筆するブログ: https://blog.rago1975.net/entry/post027/](https://blog.rago1975.net/entry/post027/)

ブログ内では以下のように書かれています。

```
puputでは、記事のフィールドの定義は、abstracts.pyの中のbody変数で行われています
```

この情報をもとに以下のように修正を行います。

```
from wagtailmarkdown.edit_handlers import MarkdownPanel
from wagtailmarkdown.fields import MarkdownField
```

変更前

```
class EntryAbstract(models.Model):
    body = RichTextField(verbose_name=_('body'))
```

変更後

```
class EntryAbstract(models.Model):
    body = MarkdownField(blank=True)
    verbose_name=_('body')
```

そしてentry_page.htmlとblog_page.htmlにこんな感じでmarkdownが表示できるように追記します。

blog_page.htmlの場合


```
{% load wagtailmarkdown %}
```

中略

```
<meta property="og:description" content="{{ blog_page.description|markdown }}" />
```

entry_page.htmlの場合

```
{% load wagtailmarkdown %}
```

中略

```
{{ self.body|markdown}}
```

こんな感じで「|markdown」と付け加えてあげるだけでそこがmarkdownとして表示されるようになります。これで実際にmarkdownの記事を書いてみると実際に表示されました。ここまであまりコーディングもせずにmarkdownの搭載ができました。プラグインは便利ですね。


## CordRedCMSを追加する

例のごとくrequirements.txtを編集していきます。ベースイメージはrequirements.base.txtでDjangoのところまでつくり、こちらのrequirements.txtはdjangoのカスタマイズのためのインストール内容を記載しています。わざわざバージョンまで書き込んでいるのは完全にインフラおじさんとしての癖なのでゆるしてください。動くバージョン、再現性というところを意識していますがあまり関係はない気はします。markdownもcoderedcmsもver1.0を超えてはいませんからね......

```
wagtail==2.6.2
puput==1.0.5
wagtail-markdown==0.5
wagtailfontawesome==1.1.4
coderedcms==0.16.3
```

このあとさらにcmssiteというディレクトリをdjangoアプリとしてつくります。ここまでくれば前あった二つのプロジェクトファイル群は捨てることができました。gitにものすごい使わないコードが溜まり込んでましたからね......

```
[VM]# docker-compose exec django /bin/bash
[Ctr]# coderedcms start cmssite --sitename "Distributed-Novel-Application-by-Git"
```

完了するとCodeRedさんは親切に次にやることを教えてくれます。いい会社。

```
Next steps:
    1. cd cmssite/
    2. python manage.py migrate
    3. python manage.py createsuperuser
    4. python manage.py runserver
    5. Go to http://localhost:8000/admin/ and start editing!
```

しかしこのコンテナを使っている以上ステップとしてはこんな感じに変わります。ほぼ本番環境運用できるレベルのものをつくっているからね。しょうがない。

```
Next steps(this container):
    1. cd cmssite/
    2. python manage.py migrate
    3. python manage.py createsuperuser
    3.1 base.pyのDatabases変更
    3.2 INSTALLED_APPSのpuput追加とPUPUT_AS_PLUGIN = Trueの追記
    3.3 url.pyの書き直し
    3.4 python manage.py collectstatic
    3.5 gunicorn(ruby on railsのunicornみたいなやつらしいです)コマンドの書き直し
    4. docker-compose downとup(再起動)
    5. Go to http://localhost:8000/admin/ and start editing!
```

3.まで普通にやります。

```
1. cd cmssite/
2. python manage.py migrate
3. python manage.py createsuperuser
```

ここからは前回の記事のように変更を行います。

### 3.1 base.pyのDatabases変更

本番運用するときはここはDB共々変えた方がいいですね......

```
DATABASES = {
    'default': {
        "ENGINE": "django.db.backends.postgresql_psycopg2",
        #'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'postgres',  #作成時のデフォルト
        'USER': 'postgres',  #作成時のデフォルト
        'PASSWORD' : 'hogemojahogemoja', #作成時にdocker-compose.ymlで設定
        'HOST' : 'postgres', #コンテナのサーバ名
        'PORT' : 5432,
    }
}
```


### 3.2 INSTALLED_APPSのpuput追加とPUPUT_AS_PLUGIN = Trueの追記

例の如く追記していきます。

```
INSTALLED_APPS = [
    # 中略

    #puput
    'wagtail.contrib.sitemaps',
    'wagtail.contrib.routable_page',
    'django_social_share',
    'puput',
    'colorful',

    #Markdown
    'wagtailmarkdown',
```

これも必須です。ないとpage not found(404)に苦しめられます。

```
PUPUT_AS_PLUGIN = True
```

### 3.3 url.pyの書き直し

re_pathでcoderedcmsは書かれているものの郷に従いません。urlとre_pathの違いがわかったら帰ってきます......どうやらdjango2系からスタートした書き方みたいで、こっちの方が使いやすいらしいです。

```
from django.conf.urls import include, url
from wagtail.core import urls as wagtail_urls
from django.conf.urls import url
from puput import urls as puput_urls
中略
url(r'',include(puput_urls)),
url(r'', include(wagtail_urls)),
```


### 3.4 manage.py collectstatic

ものすごくファイルがコピーされます。このファイル群はnginxから出されるようになりますが、逆にcssなどが変更があるたびにこのコマンドを実行する必要があります。

```
[Ctr]:/opt/apps/cmssite# python manage.py collectstatic

435 static files copied to '/opt/apps/cmssite/static'.
```

### 3.5 gunicorn(ruby on railsのunicornみたいなやつらしいです)コマンドの書き直し

今度は元祖docker-compose.ymlの編集です。プロジェクトディレクトリを書き直しておきます。これでrunserverのもっとしっかりしたgunicornが動きます。ただしここにあるwsgi.pyを見ればわかりますが現在動作するのはbase.pyとdev.pyです。いずれprod.pyを本番で運用するようにしないといけません。

変更前

```
command: bash -c "cd mysite && gunicorn mysite.wsgi -b 0.0.0.0:3031"
```

変更後

```
command: bash -c "cd cmssite && gunicorn cmssite.wsgi -b 0.0.0.0:3031"
```

## docker-composeのstaticファイルの参照箇所の更新

盲点で若干はまりましたが、こんな感じでnginx内のdjangoの方だけ書き直しました。

```
nginx:
#中略
volumes:
  - "./nginx/:/etc/nginx/"
  - "./django/cmssite/static:/opt/apps/static/"
```

## 4. docker-compose downとup(再起動)

準備が整ったので再起動をかけます。

```
[VM]# docker-compose down
[VM]# ocker-compose up -d
```

見た目そのものはあまり違いがあるようには見えませんが、かなり機能が追加されております。すごい......

<img width="1429" alt="スクリーンショット 2019-10-20 17.39.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431414/7f0d124a-e4c9-146d-4f9c-4c8a5cc02d36.png">

<img width="1439" alt="スクリーンショット 2019-10-20 17.39.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431414/f38260a4-ae35-edb9-4c16-3d376797db5c.png">

<img width="1437" alt="スクリーンショット 2019-10-20 17.40.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431414/da5c3372-6251-145a-adc2-bbb318321a16.png">

<img width="1444" alt="スクリーンショット 2019-10-20 17.41.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431414/fa5611b6-82df-c5fd-78fd-739ce7bcef64.png">



## おわりに
ついにCMSらしいCMSが使えるようになりました。またmarkdown表示機能も導入できたので、これでmarkdownベースで作品を投入できるようになります。

はじめは人のdocker-composeファイル群を拝借し、Django Girls Tutorialをがんばるするところから始まりましたが、要所に正確にPythonコードを打ち込むだけでだいぶ魔改造ができるようになってやりたいことができるようになってきました。いい時代になったなという印象です。それもこれも情報を公開してくれている方々のおかげなのでありがたいですね。

ここからは作品を投稿しやすくする機能と同時に、このdocker-composeをk8sで本格的に運用できるようにしていきます。現状だとVM一機が止まればすぐ終わりで、フェイルオーバーもスケーリングも難しいので......もともとvSphere触っててこのあたりのことは片付けておきたいと常々思っていたのでようやく本格的に取り掛かるためのアプリができたかなという感じです。

またログファイルやpostgreSQL,Nginxのコンフィグも事前にチューニングをかけたりして最適に使えることを目指していきます。このあたりは専門外なのですが、コンテナでインフラもアプリも書く以上避けては通れない道なのでここで理解してこのアプリのコードに反映させていきます。正直楽しみです。