Wagtailを触ってみた(1)、saveメソッドをオーバーライドしよう。

#### はじめに
こんにちは

少し前にWagtailを使って開発をしていました。Wagtailの日本語の文献はあまり多くないので、英語の文献を読むことが求められます。

エンジニアとしては英語の文献を読む力は非常に重要ではありますが、
**日本語で書かれた文献があればなぁ**
と多くの方が思うはずではないでしょうか。~~僕は思います~~

というわけで、Wagtailを使ってコードを書いて、それをアウトプットしていきたいと思います。
今回はそれの第一弾です。

---

#### Wagtailについて
そもそもWagtailって何って思われる方もいると思います。

WagtailはDjangoベースで開発された[CMS](https://www.asobou.co.jp/blog/web/about-cms)の[OSS](https://wa3.i-3-i.info/word15874.html)です。WordPressがPHPで動いているのに対して、WagtailはPythonで動いています。[リリースノート](http://docs.wagtail.io/en/v2.7/releases/)を見れば分かるように、開発が結構盛んに行われていますね。

ちなみに、Wagtailは日本語ではセキレイにあたる言葉です。Wagtailのロゴもセキレイをモチーフにして作られていますね。

---

#### 環境を整えよう
早速触っていきましょう。
僕はmacでやってます。環境構築に関しては下記サイトを参考にしました。

参考：
[Wagtailのすすめ(1) DjangoベースのCMSを比較・検討してWagtailを選択した話](https://qiita.com/j54854/items/96396f24fe8ce9b60d05)
[wagtailで簡単なブログシステムを作る~Learn Wagtail ①](https://qiita.com/yinawekuky/items/52343fa12850f84ee79e)

---

#### 本文を書き込めるようにしよう
localhostからCMSにアクセスして、「Pageボタン」をクリックしましょう。次に、画面上部にある「ADD CHILD PAGE」をクリックします。ここではブログの編集ができます。

コードを何も編集していない状態であれば、タイトルしか記入できません。下記の参考サイトを参考にして、本文を書き込めるように設定します。

参考：[Wagtailのページカスタマイズ](https://tech.shiroshika.com/wagtail-homepage-plugin/)

```python:home/models.py

  1 from django.db import models
  2 
  3 from wagtail.core.models import Page
  4 from wagtail.core.fields import RichTextField
  5 from wagtail.admin.edit_handlers import FieldPanel
  6 
  7 
  8 class HomePage(Page):
  9     """
 10     Pageのモデル
 11     """
 12     body = RichTextField(blank=True)
 13     content_panels = Page.content_panels + [FieldPanel("body", classname="full"),]

```
コードを見てみましょう。このモデルのコードには、[Page](https://github.com/wagtail/wagtail/blob/c72a4e09413bc6fc3a9cac8ed173378aa8652925/wagtail/core/models.py#L231)モデルを[継承](https://blog.codecamp.jp/python-class-2)したHomePageモデルが書かれていますね。[RichTextField](https://github.com/wagtail/wagtail/blob/c72a4e09413bc6fc3a9cac8ed173378aa8652925/wagtail/core/fields.py#L9)としてのbody、つまり本文のモデルを追加しました。[FieldPanel](https://github.com/wagtail/wagtail/blob/c72a4e09413bc6fc3a9cac8ed173378aa8652925/wagtail/admin/edit_handlers.py#L420)の追記を忘れないようにしましょう。~~忘れた人がここにいます~~

マイグレーションもしておきましょう。

```shell

python manage.py makemigrations
python manage.py migrate
```



表示画面はこんな感じになってると思います。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
<img width="713" alt="スクリーンショット 2019-12-23 15.24.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517540/fb465b6f-ea65-ba25-4b1d-7f1dd2f7e8e4.png">

---

#### タイトル、本文保存時の動作を書いてみよう
タイトルや本文を記入したら、画面下部にあるタブをクリックしてコンテンツを保存できます。その際の処理として、タイトルや本文にバリデーションをかけてみます。今回は文字数に制限をかけてみます。
**テストのために、タイトルと本文を保存しておきましょう**

```python:home/models.py
  1 from django.db import models
  2 
  3 from wagtail.core.models import Page
  4 from wagtail.core.fields import RichTextField
  5 from wagtail.admin.edit_handlers import FieldPanel
  6 
  7 
  8 class HomePage(Page):
  9     """
 10     Pageのモデル
 11     """
 12     body = RichTextField(blank=True)
 13     content_panels = Page.content_panels + [FieldPanel("body", classname="fu    ll"),]
 14 
 15     def save(self, *args, **kwargs):
 16         """save関数"""
 17         print("save関数に入りました")
 18         breakpoint()
```

[django](https://docs.djangoproject.com/ja/3.0/)の[saveメソッド](https://qiita.com/sakamossan/items/44f54d287d13334e6406)をオーバーライドしています。



```python
breakpoint()
```
これはPythonで使えるデバッガ[PDB](https://qiita.com/nakkun/items/62cc704af729893783f1)を呼び出す関数です。早速実行してみましょう。
1. ローカルサーバを起動する
2. breakpoint()を任意の場所に記述する
3. 編集したファイルを保存する
4. 任意のコマンドを実行する
これで下記のようなログが出力されました。

```shell
save関数に入りました
--Return--
> /Users/Username/mysite/home/models.py(18)save()->None
-> breakpoint()
(Pdb) HomePage
<class 'home.models.HomePage'>
(Pdb) HomePage.objects
<django.db.models.manager.BasePageManagerFromPageQuerySet object at 0x10ebee410>
(Pdb) HomePage.objects.all()
<PageQuerySet [<HomePage: Home>, <HomePage: title>]>
(Pdb) instance = HomePage.objects.all()
(Pdb) instance
<PageQuerySet [<HomePage: Home>, <HomePage: title>]>
(Pdb) instance[1]
<HomePage: title>
(Pdb) instance[1].title
'title'
(Pdb) len(instance[1].title)
5

```
[len関数](https://note.nkmk.me/python-str-len/)を使えば文字列の長さが分かりますね。

DjangoやWagtailで開発をする場合、僕はこんな感じでデバッガを起動してオブジェクトの中身を確認します。あとは条件式を書けば、タイトルの文字数のバリデーションがかけれそうですね。

このサイト「[Google SEOで効果的なタイトルの文字数とは](https://www.sakurasaku-labo.jp/blogs/tittle-word-count)」によれば、タイトル文字は32文字ぐらいまでがちょうどいいみたいですね。今回は33文字を超えないように処理したいと思います。

```python:home/models.py
 16     def save(self, *args, **kwargs):
 17         """save関数"""
 18         print("save関数に入りました")
 19         breakpoint()
 20         instance = HomePage.objects.all() # 消し忘れです
 21         titleCharCount = len(self.title)
 22         if ((titleCharCount < 0) | (titleCharCount > 32)):
 23             #バリデーションが通っていない
 24             return
 25         else:
 26             #バリデーションが通った
 27             return super(HomePage, self).save()

```

24行目ではオブジェクトは保存されません。27行目で保存されます。デバッガを使って確認してみましょう。同じような処理を書けば、本文にもバリデーションがかけられるでしょう。

---
#### さいごに
オブジェクトが保存できない時に画面上部に表示されるエラーメッセージが実装できていませんね。
次回はそれのアウトプットを書きたいと思います。