Kuzunoha-NEのブログ

pythonの勉強中。

【Python】FlaskのJinja2と別でimportしたJinja2を使って文字の置換を二回行う

こんばんは、葛の葉です。

Flaskの文字置換を二段階にわけて行いたい場合の方法を書きます。

環境

python 3.6.5

flask 1.0.2

jinja2 2.10

やり方の説明

元のhtml -> custom_jinja -> flaskのjinja2 できれいにする。

custom_jinjaでは::で挟んだ変数を読み込む

flaskのjinja2では{{}}で挟んだ変数を読み込む

jinja2とjinja2.Environmentを使う

flask内のjinja2とはのjinja2を使用する。

その別のjinja2を便宜的にカスタムjinjaと呼ぶことにする。

jinja2.Environment()内の引数にある以下の値を変更、それをカスタムjinjaというインスタンスとして扱う。

variable_start_stringは変数を囲う最初の文字

variable_end_stringは変数を囲う最後の文字

custom_jinja = jinja2.Environment(
    loader=jinja2.FileSystemLoader('templates'),
    variable_start_string=':',
    variable_end_string=':'
)

説明が前後したけど、loader=jinja2.FileSystemLoader('templates')はtemplateファイルを読み込むディレクトリ名をtemplatesにしています。

page = custom_jinja.get_template('index.html')

と、このようにすることで、templateファイルを読み込めます。

render_template = pages.render(variable_name='value')

と、することでvariable_nameの変数をtemplateファイルに送ることができます。

こんな感じ

sandbox_flask.py
templates/
    ├index.html
    └layout.html

sandbox_flask.py

from flask import Flask, render_template, render_template_string
import jinja2

app = Flask(__name__)

custom_jinja = jinja2.Environment(
    # 元htmlの保存されているディレクトリ名。flaskと併用するので以下の値。
    loader=jinja2.FileSystemLoader('templates'),

    #デフォルトでは{%にあたるもの。flaskのjinjaと重複しない値にする。
    block_start_string='[{[{[Q',
    #デフォルトでは%}にあたるもの。flaskのjinjaと重複しない値にする。
    block_end_string='Q]}]}]', 
    
    # このvariable...と続くステータスを挟みたい文字にする。
    variable_start_string=':',
    variable_end_string=':',

    # オートエスケープは特殊文字等をエスケープします。
    autoescape=False)


# 定数のようなもの。:Key: -> Value にしてくれる。
SPECIAL_CONVERSION_CHARACTER = {
    'test': '!TesT!'
}
# SPECIAL_CONVERSION_CHARACTERが不要ならここの処理も不要
custom_jinja.globals.update(SPECIAL_CONVERSION_CHARACTER)


@app.route("/")
def hello():

    # index.htmlを元にhtmlを生成します。
    page = custom_jinja.get_template('index.html')

    template = page.render(name='サンプルタイガー')

    return render_template_string(template, name='サンプルドラゴン', title='Titleだよ!!!')

if __name__ == "__main__":
    app.run(debug=True)

layout.html

<!doctype html>
<html>

<head>
    <meta http-equiv="content-type" charset="utf-8">
    <title>{{ title }}</title>
</head>

<body>
    {% block content %}
    {% endblock %}
</body>

<footer>
</footer>

</html>

index.html

{% extends "layout.html" %}
{% block content %}

<p>
    :':name:':=:name:<br>
    {{ '{{ name }}' }}={{ name }}<br>
</p>

:test:

{% endblock %}

表示はこんな感じ

:name:=サンプルタイガー
{{ name }}=サンプルドラゴン
!TesT!

f:id:Kuzunoha-NE:20181228230746p:plain

STR型を変換する

bunsho = ':one:である :two:なのだ'

以下のような辞書を参照してAである Bなのだという文字列にしたい場合

{'one': 'A','two': 'B'}

importやcustom.jinjaなどの記載省略
...

@app.route("/")
def hello():
...省略...

@app.route("/x")
def xstring():

    string = custom_jinja.from_string(':one:である :two:なのだ ')
    strings = string.render(
        {
            'one': 'A',
            'two': 'B'
        }
    )
    return render_template('strings.html', strings=strings)
...

strings.html ( {{ strings }}と書かれているだけのhtml)

{{ strings }}

出力するとこうなる

Aである Bなのだ

出来なかった個所

key名が数字のみ場合は参照されない。

    string = custom_jinja.from_string(':1:である :2:なのだ ')
    strings = string.render(
        {
            '1': 'A',
            '2': 'B'
        }
    )
    return render_template('strings.html', strings=strings)

-> 1である 2なのだ