2019/06/26
Python Django Markdown【Django】 HTMLタグ、MarkDown エディタで投稿できるようにする
Djangoでテキストを投稿するときに、HTMLタグやMarkDown記法で書けるようにする方法です。
こんなアプリがあったとします。
models.py
class Blog(models.Model):
title = models.CharField(max_length=40)
text = models.TextField()
views.py
def index(request, id):
blog = Blog.objects.get(id=id)
return render(request, 'blog.html', {"blog": blog})
blog.html
<h1>{{ blog.title }}</h1>
<div>
{{ blog.text }}
</div>
admin画面ではこのように表示され、テキストを入力することができます。
入力されたテキストはこのように表示されますが、当然文字の大きさや色を変えて装飾することはできません。
文字を装飾するためには、HTMLやMarkDownの記法で入力します。
HTMLタグで入力できるようにする
文字をHTMLタグで囲って保存してみます。
すると、タグがエスケープされて、画面にはHTMLタグがそのまま表示されてしまいます。。。
HTMLタグとして読み込むためには、safe
というテンプレートタグを使います。
blog.html
<h1>{{ blog.title }}</h1>
<div>
{{ blog.text |safe }}
</div>
これでHTMLタグを読み込めるようになりました。classやidを付与することで、cssを適用することもできます。
また、以下のように特殊文字を使うことでHTMLタグをそのまま画面に表示させることもできます。
MarkDownで入力できるようにする
HTMLタグで書く方法でも良いのですが、いちいちタグで囲っていくのはかなり面倒です。より楽にできるようにMarkDownでも書けるような設定をしてみます。
Python-MarkDownパッケージを使います。これは、MarkDown記法で書かれたものをHTML形式に変換できるパッケージです。細かい使い方はドキュメントにあります。
Python-Markdownの使い方
# インストール
$ pip install markdown==3.1.1
# MarkDownで書かれたものをHTMLに変換する
$ python3
>>> from markdown import markdown
>>> markdown('#見出し1')
'<h1>見出し1</h1>'
>>> markdown('テキストです')
'<p>テキストです</p>'
>>> markdown('[リンクです](http://sample.com)')
'<p><a href="http://sample.com">リンクです</a></p>'
このように、markdown( )
関数の引数にMarkDown形式で書いた文字列を渡すと、HTML形式に変換して返してくれます。また、HTMLを引数に取った場合は、そのままHTMLを返します。
HTMLを引数にした場合
>>> markdown('<h1>見出し1</h1>')
'<h1>見出し1</h1>'
Djangoで使ってみる
markdown( )
関数をmodels.pyで使ってみます。これによって、MarkDownで入力されたテキストを、HTMLに変換した形でテンプレート(blog.html)に渡すことができます。
models.py
from django.db import models
from markdown import markdown # 追加
class Blog(models.Model):
title = models.CharField(max_length=40)
text = models.TextField()
def get_markdown_text_as_html(self):
"""MarkDown記法で書かれたtextをHTML形式に変換して返す"""
return markdown(self.text)
blog.html
<h1>{{ blog.title }}</h1>
<div>
{{ blog.get_markdown_text_as_html | safe }}
</div>
これで、MarkDownで入力できるようになりました。入力した文字はHTMLに変換されて読み込まれます。
id名、class名を付与する
extensions=['attr_list']
とすることで、idやclassなどを指定することができます。詳しい書き方はこちら。
これにより、MarkDownで書かれたものにもCSSを適用することができます。
Python-Markdownでid名、class名を付与する方法
>>> markdown('## 見出し2 {#title-2}', extensions=['attr_list'])
'<h2 id="title-2">見出し2</h2>'
>>> markdown('文章です\n{.text}', extensions=['attr_list'])
'<p class="text">文章です</p>'
>>> markdown('[リンク](sample.com){.link}', extensions=['attr_list'])
'<p><a class="link" href="sample.com">リンク</a></p>'
hタグにid, classを付与する場合は見出しの後ろに1つスペースを入れる必要があります。
pタグのようなブロック要素の後には改行が必要なので\n
と入れています。admin画面上では\n
と入れなくても、改行して1行下に{.text}
と書いてあげれば大丈夫です。
GitHubっぽくcodeを書く
Python-MarkDownではデフォルトで、スペース4つかタブ1つをつけることによって、コードとみなされます。
codeタグに変換する
>>> markdown(" print('hello')")
"<pre><code>print('hello')\n</code></pre>"
admin画面でも、同じようにスペースを空けることでコードとして書くことができます。
スペースを空けるのではなく、GitHubのようにコードを```
で囲みたいときはextensions
にfenced_code
を追加します。
models.py
from django.db import models
from markdown import markdown
class Blog(models.Model):
title = models.CharField(max_length=40)
text = models.TextField()
def get_markdown_text_as_html(self):
"""MarkDown記法で書かれたtextをHTML形式に変換して取得する"""
return markdown(self.text, extensions=['fenced_code', 'attr_list']) # fenced_codeを追加
admin画面でこのように入力できるようになる
```python
print('hello')
```
HTMLに変換される
<pre><code class="Python">print('hello')</pre></code>
コードをハイライトする
コードと認識した部分をハイライトしたい場合は、highlight.jsというライブラリを使うと便利です。<pre>
タグと<code>
タグで囲まれた部分をいい感じにハイライトしてくれます。
使い方はHTMLファイルでこのように読み込むだけです。
highlight.jsを読み込む
<h1>{{ blog.title }}</h1>
<div>
{{ blog.get_markdown_text_as_html | safe }}
</div>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.8/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.8/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
外部パッケージで拡張する
fenced_code
のようにデフォルトでサポートされているもの以外でも、外部パッケージをインストールすればよりGitHubに近い書き方ができるようになります。