cdxy.me
Footprints on cyber security and Python

思路

  • 前端加载Markdown编辑器,数据通过POST传数据到后端并存入数据库。
  • 后端取出数据,在模板中将Markdown解析为HTML再输出给用户。

在线编辑器

使用开源产品: Editor.md

安装

从github下载zip,解压重命名为editormd,并置入Flask的static文件夹。

路由

model.py

@main_blueprint.route('/test1')
def test_1():
    mkd = '''
    # header
    ## header2
    [picture](http://www.example.com)
    * 1
    * 2
    * 3
    **bold**
    '''

    return render_template('test_1.html', mkd=mkd)

模板

注意使用url_for()导入css和js文件,并以其中一个div的id值初始化editormd(),这个div即显示为在线编辑器。

test_1.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="utf-8"/>
    <title>Simple example</title>
    <link rel="stylesheet" href="{{ url_for('static',filename='editormd/css/editormd.css') }}"/>
</head>
<body>

<div id="test-editormd">
</div>
<script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
<script src="{{ url_for('static',filename='editormd/editormd.min.js') }}"></script>
<script type="text/javascript">
    var testEditor;

    $(function () {
        testEditor = editormd("test-editormd", {
            width: "90%",
            height: 640,
            syncScrolling: "single",
            path: "{{ url_for('static',filename='editormd/lib/') }}"
        });
    });
</script>
</body>
</html>

效果

运行Flask之后访问路由效果:

效果图

解析器

解析器使用 Flask-Markdown 插件

安装

pip install flask-markdown

使用

绑定app

from flask_markdown import Markdown

app=Flask(__name__)
Markdown(app)

然后在Jinja中使用过滤器将Markdown转为HTML

{{post.text|markdown|safe}}

实例

使用Flask-WTF设置<textarea>标签存放文章内容。

forms.py

class PostForm(FlaskForm):
    title = StringField('Title', [DataRequired(), length(max=255)])
    text = TextAreaField('Content', [DataRequired()])
    categories = SelectMultipleField('Categories', coerce=int)

    def __init__(self):
        super(PostForm, self).__init__()
        self.categories.choices = [(c.id, c.title) for c in Category.query.order_by('id')]

从库中查出文章内容,并将其赋予Form的<textarea>标签,传入模板文件。

controller/blog.py

@login_required
@blog_blueprint.route('/edit/<int:id>', methods=['GET', 'POST'])
def edit_post(id):
    p = Post.query.get_or_404(id)

    if current_user != p.user:
        abort(403)

    form = PostForm()

    if form.validate_on_submit():
        p.title = form.title.data
        p.text = form.text.data
        p.modified_date = datetime.datetime.now()

        db.session.add(p)
        db.session.commit()
        flash('Edit Saved.', category='success')
        return redirect(url_for('.post', id=p.id))

    form.title.data = p.title
    form.text.data = p.text
    return render_template('edit.html', form=form, post=p)

模板中将编辑器与我们Form中的<textarea>组合。

post_edit.html

{% extends "base.html" %}
{% block title %}Edit Post{% endblock %}
{% block body %}
    <link rel="stylesheet" href="{{ url_for('static',filename='editormd/css/editormd.css') }}"/>
    <div class="row">
        <h1 class="text-center">Edit Post</h1>

        <form method="post" action="{{ url_for('.edit_post',id=post.id) }}">
            {{ form.hidden_tag() }}
            <div class="form-group">
                {{ form.title.label }}
                {% if form.title.errors %}
                    {% for e in form.title.errors %}
                        <p class="help-block">{{ e }}</p>
                    {% endfor %}
                {% endif %}
                {{ form.title(class_='form-control') }}
            </div>

            <div class="form-group">
                {{ form.text.label }}
                {% if form.text.errors %}
                    {% for e in form.text.errors %}
                        <p class="help-block">{{ e }}</p>
                    {% endfor %}
                {% endif %}
                <div id="editormd" class="form-control">
                    {{ form.text(style="display:none;") }}
                </div>
            </div>
            <input class="btn btn-primary" type="submit" value="Edit">
        </form>
    </div>
{% endblock %}

{% block js %}
    <script src="{{ url_for('static',filename='editormd/editormd.min.js') }}"></script>
    <script type="text/javascript">
        var testEditor;

        $(function () {
            testEditor = editormd("editormd", {
                width: "100%",
                height: "100%",
                syncScrolling: "single",
                path: "{{ url_for('static',filename='editormd/lib/') }}"
            });
        });
    </script>

{% endblock %}

最终效果

效果图

现在使用这个编辑器输入的数据将以Markdown格式存入数据库。

接下来在解析页面的模板中加入markdown过滤器即可。

<div class="col-lg-12 post-text">
     {{ post.text|markdown|safe }}
</div>

页面效果(也就是本篇文章的效果)

效果图

Tip

Flask-Markdown使用Python第三方库Markdown解析,其默认不识别三个反引号的code-block,需开启扩展。

import markdown

def markdown2html(text):
    return markdown.markdown(text, ['extra'])