自ら環境を構築して執筆するブログ

Puput の導入と設定

このサイトでは、Wagtailで動くブログツールとしてPuputを使用しています。Puputの導入・設定等について説明します。

Puputはpipでインストールできます。Puputの公式ドキュメントを参考にして、設定します。(Wagtailは既にインストールされている前提です。)


$ pip install wheel
$ pip install django-colorful django-el-pagination django-social-share
$ pip install --no-deps puput

Wagtail のsettings/base.py(作成したプロジェクトがmyprojectである場合myproject/myproject/settings/base.py)を編集し、INSTALLED_APPSに以下を追加ます。


'puput',
'colorful',

また、myproject/myproject/settings/base.pyに以下の行を追加します。


PUPUT_AS_PLUGIN = True

さらに、myproject/myproject/urls.pyurl(r'', include(wagtail_urls)),という行の前に以下の行を追加します。


url(r'',include(puput_urls)),

その後、myprojectのディレクトリで./manage.py migrateを実行し、その後、再起動させます。

pip でインストールしたpuput は~/.pyenv/versions/3.7.0/lib/python3.7/site-packages/puput/ に展開されています(pyenv でインストールしたpythonのバージョンが3.7.0の場合)。そのままだとカスタマイズしづらいため、~/.pyenv/versions/3.7.0/lib/python3.7/site-packages/puput/ ディレクトリごと、myprojectディレクトリにコピーしています。

PuputにおけるStreamFieldの活用

Wagtailの特徴として、様々なフィールドを組み合わせて記事を作成することができます。詳細はWagtailのドキュメントに記されています。

puputでは、記事のフィールドの定義は、abstracts.pyの中のbody変数で行われています。上記のWagrtailのドキュメントを参考に、abstracts.pyを編集してみます。例えば、Richtext ブロック(WYSIWYGエディタで編集するブロック)とRawHTMLブロック(コード等、HTMLをタグ打ちで編集するブロック)が混在する場合、abstracts.pyをこのように編集してみます。


import datetime

from django.db import models
from django.utils.translation import ugettext_lazy as _

from wagtail.admin.edit_handlers import FieldPanel, MultiFieldPanel, InlinePanel, PageChooserPanel, StreamFieldPanel
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtail.core.fields import RichTextField, StreamField

from wagtail.core import blocks

from modelcluster.contrib.taggit import ClusterTaggableManager

from .utils import get_image_model_path


class EntryAbstract(models.Model):
    body = StreamField([
        ('paragraph', blocks.RichTextBlock()),
        ('htmlcode', blocks.RawHTMLBlock()),
    ],verbose_name=_('body'))
    tags = ClusterTaggableManager(through='puput.TagEntryPage', blank=True)
    date = models.DateTimeField(verbose_name=_("Post date"), default=datetime.datetime.today)
    header_image = models.ForeignKey(
        get_image_model_path(),
        verbose_name=_('Header image'),
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    categories = models.ManyToManyField('puput.Category', through='puput.CategoryEntryPage', blank=True)
    excerpt = RichTextField(
        verbose_name=_('excerpt'),
        blank=True,
        help_text=_("Entry excerpt to be displayed on entries list. "
                    "If this field is not filled, a truncate version of body text will be used.")
    )
    num_comments = models.IntegerField(default=0, editable=False)

    content_panels = [
        MultiFieldPanel(
            [
                FieldPanel('title', classname="title"),
                ImageChooserPanel('header_image'),
                StreamFieldPanel('body', classname="full"),
                FieldPanel('excerpt', classname="full"),
            ],
            heading=_("Content")
        ),
        MultiFieldPanel(
            [
                FieldPanel('tags'),
                InlinePanel('entry_categories', label=_("Categories")),
                InlinePanel(
                    'related_entrypage_from',
                    label=_("Related Entries"),
                    panels=[PageChooserPanel('entrypage_to')]
                ),
            ],
            heading=_("Metadata")),
    ]

    class Meta:
        abstract = True