---
slug: "Mezzanineで、reStructuredtextを使う"
title: "Mezzanine で、reStructured text を使う"
description: "\n\n\nPython + Django 上で CMS を構築する、 Mezzanine というシステムがあります。\nブログエントリは標準形式では WYSIWYG な HTML エディタで書きますが、\nreStructured Text (reST, rst) で書きたかったため調べてみました。"
url: "https://www.ytyng.com/blog/Mezzanineで、reStructuredtextを使う"
publish_date: "2015-05-10T07:19:19Z"
created: "2015-05-10T07:19:19Z"
updated: "2026-02-27T10:53:56.708Z"
categories: ["Django"]
keywords: ""
featured_image_url: "https://media.ytyng.com/resize/20230812/ad19f15637a74a79b22f26796801c0cb.png.webp?width=768"
has_video: false
has_music: false
video_urls: []
music_urls: []
lang: "ja"
---

# Mezzanine で、reStructured text を使う

<div class="document">


<p>Python + Django 上で CMS を構築する、 Mezzanine というシステムがあります。
ブログエントリは標準形式では WYSIWYG な HTML エディタで書きますが、
reStructured Text (reST, rst) で書きたかったため調べてみました。</p>
<p>pygments でコードシンタックスハイライティングもしてくれるようになるため、便利です。</p>
<p>環境としては</p>
<ul class="simple">
<li>Python 3.4</li>
<li>Django==1.6.11</li>
<li>Mezzanine==3.1.10</li>
<li>mezzanine-meze==0.3</li>
<li>Sphinx==1.3.1</li>
</ul>
<p>です。これを書いている 2015年5月現在、Django は 1.8 が使えるのですが、
mezzanine が Django 1.6 までしか対応していなためこのようなバージョンになっています。</p>
<p>後述しますが、これでは Sphinx と mezzanine-meze のバージョン関係に不具合があります。</p>
<div class="section" id="mezzanine">
<h3>1. Mezzanine のインストール</h3>
<p>mezzanine のインストール方法も書いておきます。mac 内に環境を作ります。</p>
<pre class="literal-block">$ pyvenv-3.4 .virtualenvs/my-blog
$ workon my-blog
$ pip install mezzanine  # Django ごとインストールされます
</pre>
<p>Mezzanine プロジェクトをつくるには</p>
<pre class="literal-block">$ mezzanine-project my_blog
</pre>
</div>
<div class="section" id="restructured-text-mezzanine-meze">
<h3>2. reStructured Text 用ライブラリ mezzanine-meze のインストール</h3>
<p>mezzanine-meze をインストールします。これは、ブログ記事の保存時、
Sphinx を使って reST からHTMLを生成するようになります。</p>
<pre class="literal-block">pip install pip install mezzanine-meze
</pre>
</div>
<div class="section" id="id1">
<h3>3. 設定</h3>
<p><a class="reference external" href="https://github.com/abakan/mezzanine-meze">https://github.com/abakan/mezzanine-meze</a></p>
<p>ここにある通り、設定をしていきます。</p>
<div class="section" id="installed-apps">
<h4>3-1. INSTALLED_APPS の登録</h4>
<p>settings.py の INSTALLED_APPS に、meze を追加</p>
</div>
<div class="section" id="id2">
<h4>3-2. 追加フィールドの登録</h4>
<p>settings.py の下部に追記</p>
<pre class="literal-block">help_text = ("Source in reStructuredText format will be converted to "
             "HTML and result will replace content field.")
EXTRA_MODEL_FIELDS = (
    # Enable Meze for blog posts
    ("mezzanine.blog.models.BlogPost.source",
     "TextField", (), {"blank": True, "help_text": help_text}),
    ("mezzanine.blog.models.BlogPost.convert",
     "BooleanField", ("Convert source",), {"default": True}),
    # Enable Meze for rich text pages
    ("mezzanine.pages.models.RichTextPage.source",
     "TextField", (), {"blank": True, "help_text": help_text}),
    ("mezzanine.pages.models.RichTextPage.convert",
     "BooleanField", ("Convert source",), {"default": True}),
)
del help_text
</pre>
</div>
<div class="section" id="meze-settings-sphinx-conf">
<h4>3-3. MEZE_SETTINGS, SPHINX_CONF の登録</h4>
<p>settings.py の下部に追記</p>
<pre class="literal-block">MEZE_SETTINGS = {
    'workdir': os.path.join(PROJECT_ROOT, 'meze_workdir'),
}

SPHINX_CONF = """
project = u''
copyright = u''
version = '0'
release = '0'
master_doc = 'index'
pygments_style = 'sphinx'
html_theme = 'default'
html_sidebars = {'**': []}
html_domain_indices = False
html_use_index = False
html_show_sourcelink = False
html_add_permalinks = None
source_suffix = '.rst'
intersphinx_mapping = {'python': ('http://docs.python.org/', None)}
extlinks = {'wiki': ('http://en.wikipedia.org/wiki/%s', ''),}
extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.extlinks']
"""
</pre>
</div>
<div class="section" id="html">
<h4>3-4. HTMLテンプレートの修正</h4>
<p>HTMLテンプレート (例: base.html) に、Pygments の設定を追加します。</p>
<pre class="literal-block">{% compress css %}
...
&lt;link rel="stylesheet" href="{% static "meze/css/meze.css" %}"&gt;
&lt;link rel="stylesheet" href="{% static "meze/css/pygments.css" %}"&gt;
...
</pre>
<pre class="literal-block">{% compress js %}
...
&lt;script src="{% static "meze/js/copybutton.js" %}"&gt;&lt;/script&gt;
...
</pre>
</div>
<div class="section" id="id3">
<h4>3-5. 追加ライブラリのインストール</h4>
<p>実行時、不足しているライブラリをインストールします。</p>
<pre class="literal-block">$ pip install sphinx
$ pip install south
</pre>
</div>
<div class="section" id="db">
<h4>3-6. DBマイグレーション</h4>
<p>なぜ south をインストールしたかというと、3-2 でモデルにフィールドを追加しているため、
それを DB に反映しなければならないためです。</p>
<p>少しトリッキーな方法ですが、プロジェクト直下に、migrations ディレクトリを作って、
そこに south のマイグレーションファイルを入れ、マイグレーションさせます。</p>
<p>my_blog ディレクトリは、manage.py が含まれる Django のプロジェクトディレクトリですが、
それを django の app ディレクトリとしても認識させます。</p>
<p>settings.py の INSTALLED_APPS に my_blog を入れておき</p>
<pre class="literal-block">$ cd my_blog
$ mkdir migrations
$ touch modles.py
$ ./manage.py schemamigration blog --auto --stdout &gt;&gt; migrations/0001_blog_customization.py
$ ./manage.py schemamigration pages --auto --stdout &gt;&gt; migrations/0002_pages_customization.py
$ ./manage.py migrate my_blog
</pre>
<p>こんな感じでマイグレーションできると思います。</p>
<p>データが無い場合は、DBを全部消して、./manage.py createdb から行っても良いでしょう。</p>
</div>
</div>
<div class="section" id="id4">
<h3>4. 追加設定</h3>
<p>ここまでは、mezzanine-meze のチュートリアルにある通りなのですが、
このまま起動すると meze/meze.py の 195行目</p>
<pre class="literal-block">rst = os.path.join(workdir, 'index' + app.config.source_suffix)
</pre>
<p>ここで</p>
<pre class="literal-block">TypeError at /admin/blog/blogpost/add/

Can't convert 'list' object to str implicitly
</pre>
<p>が出てしまいます。</p>
<p>おそらく、Sphix の現行バージョンでは、app.config.source_suffix が str ではなく list に
変わったのでしょう。</p>
<p>Sphinx の昔のバージョンをインストールすれば良いかもしれませんが、私はモンキーパッチを書いて対応しました。</p>
<p>urls.py の下部かどこかで</p>
<pre class="literal-block"># Meze monkey patching

from meze.meze import os, sys, codecs, time, messages, Sphinx, SPHINX_CONF, SPHINX_CONF_APPEND
from meze.meze import Meze, MezeBuilder, MezeStream


def sphinx_build_monkey(self):
    workdir = self._workdir
    if not os.path.isdir(workdir):
        os.makedirs(workdir)

    conf = os.path.join(workdir, 'conf.py')
    with codecs.open(conf, encoding='utf-8', mode='w') as out:
        out.write(SPHINX_CONF)
        out.write(SPHINX_CONF_APPEND)

    start = time.time()
    status = MezeStream(sys.stdout)
    warning = MezeStream(sys.stderr)
    app = Sphinx(srcdir=workdir, confdir=workdir, outdir=workdir,
                 doctreedir=workdir, buildername='meze',
                 confoverrides={}, status=status, warning=warning,
                 freshenv=False, warningiserror=False, tags=[])

    if isinstance(app.config.source_suffix, (list, tuple)):
        rst = os.path.join(workdir, 'index' + app.config.source_suffix[0])
    else:
        rst = os.path.join(workdir, 'index' + app.config.source_suffix)

    with codecs.open(rst, encoding='utf-8', mode='w') as out:
        out.write(self._source)

    app.build(False, [rst])

    self._messages.append((messages.INFO, 'Source was converted '
                                          'into HTML using Sphinx in {:.2f}'.
                           format(time.time() - start)))
    for msg in warning.messages:
        items = msg.split('WARNING: ')
        if len(items) == 2:
            msg = items[1]
        self._messages.append((messages.WARNING, msg))

    self._content, MezeBuilder.context = MezeBuilder.context['body'], None


Meze.sphinx_build = sphinx_build_monkey
</pre>
<p>このように、sphinx_build メソッドを上書きしました。</p>
<p>これで、私は問題なく reStructuredText から HTML に変換できるようになりました。</p>
</div>
<div class="section" id="markdown">
<h3>5. markdown の場合</h3>
<p>ちなみに、reST ではなく markdown を扱えるライブラリとして、mezzanine-mdown というのがあります。</p>
<p>こちらの動作としては、テンプレートが HTML ファイルを生成する際のテンプレートフィルタとして、markdown -&gt; HTML の変換をしているようです。</p>
<pre class="literal-block">pip install mezzanine-mdown
</pre>
<p>ではインストールできなかった(見つからなかった)ため、</p>
<pre class="literal-block">easy_install mezzanine-mdown
</pre>
<p>でインストールしました。…が、使ってません。</p>
</div>
</div>
