よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

テンプレートエンジンとは何か?Jinja2の基本3

今回で3回目、引き続きテンプレートエンジンJinja2の基本的な使い方を見ていきます。

前回までの2回
テンプレートエンジンとは何か Jinja2の基本1 - よちよちpython
テンプレートエンジンとは何か?Jinja2の基本2 - よちよちpython
でテンプレートファイルの書き方の基本に触れたので、今回はテンプレートをロードするアプリケーション側の書き方を見ていきます。

参考
Jinja2公式 APIAPI — Jinja Documentation (2.10.x)



実行環境


Androidスマホ
termux
Python3.7
JupyterNotebook



目次




Jinja2のAPI基本形-テンプレート一体型


復習。Jinja2の一番シンプルな形は一つのPythonファイルで完結したもの。
テンプレートとテンプレート読み込みと変数の値を置き換え作業が一体化したもの。
それは次のようなコード。

from jinja2 import Template

template = Template('拝啓 {{ name }}様\n\n葉朱に染め金木犀の気纏う\nご機嫌如何でしょうか、有田哲平です。  ')
text = template.render(name='茶屋')

print(text)
拝啓 茶屋様

葉朱に染め金木犀の気纏う
ご機嫌如何でしょうか、有田哲平です。  

誰やねん…



  • jinja2ライブラリからTemplateをインポート。
  • Templateクラスにテンプレート文章を渡す。
  • renderメソッドに文章内の変数に入れるデータを渡すと置き換わる。



またはこんな書き方もできる。

from jinja2 import Environment

MY_TEMPLATE = 'こんにちは、 {{ name }}!'

env = Environment()

template = env.from_string(MY_TEMPLATE)

print(template.render(name='ハンプティーダンプティー'))
こんにちは、 ハンプティーダンプティー!



  • Templateの換わりにEnvironmentをインポートする。
  • from_string()メソッドにテンプレート文章の変数を渡す。
  • render()メソッドの所は一緒。

文章が短い場合はこれでもいい。しかし、長い文章やWebページのようなデザインを幾つも考える必要があるときは分散している方が効率的。そこで、テンプレートファイルと処理用のプログラムファイルを切り離す。



Jinja2のAPI基本形-テンプレート分離型


上のJinja2公式サイトは、テンプレートを作るデザイナーと、テンプレートをロードするAPIを実装する人が作業を分担して行う前提で書かれている。

Jinja2公式サイトに載っているAPI基本形はこんなコード。



(ここから公式サイトのコピペ的説明を自分向けにやっております。しばらく読み飛ばしてOKです。)

from jinja2 import Environment, PackageLoader, select_autoescape

env = Environment(
    loader=PackageLoader('yourapplication', 'templates'),
    autoescape=select_autoescape(['html', 'xml'])
)

Environmentに加えてPackageLoader, select_autoescapeがインポートしてある。
それがその下のenv = Environment()の中で使われている。



PackageLoader()内のyourapplicationtemplatesは、yourapplication/templatesフォルダに保存されたテンプレートファイルを読み込みますよという意味で、

select_autoescape()内はリストで渡したhtmlxmlの特殊記号を自動的にエスケープしますという意味のようだ。

これにより、デフォルト設定でテンプレート環境が作成され、yourapplication pythonパッケージ内のテンプレートフォルダーで テンプレートを検索するローダーが作成されます。さまざまなローダーを使用できます。データベースまたは他のリソースからテンプレートをロードする場合は、独自のローダーを作成することもできます。これにより、HTMLおよびXMLファイルの自動エスケープも可能になります。(公式ページの自動翻訳コピペ)

「テンプレート環境が作成され」とある。これを実行してもエラーが出るだけで、フォルダが作られたりする訳ではない。

「この環境からテンプレートをロードするには」get_template()メソッドを呼び出し、ロードされたものを返すだけでよい。


template = env.get_template('mytemplate.html')


「いくつかの変数でレンダリングするには、render()メソッドを呼び出します」


print(template.render(the='variables', go='here'))



get_template()メソッドとrender()メソッドの部分を追記する。

from jinja2 import Environment, PackageLoader, select_autoescape

env = Environment(
    loader=PackageLoader('yourapplication', 'templates'),
    autoescape=select_autoescape(['html', 'xml'])
)

template = env.get_template('mytemplate.html')

print(template.render(the='variables', go='here'))

「yourapplication」フォルダの中に「templates」フォルダを作り、更にその中に「mytemplate.html」というテンプレートファイルを置く。
テンプレートファイルには「the」と「go」の変数が使われてあるんだろう。
その通りにしてみる。



フォルダ、テンプレートファイル、Pythonファイルの作成(PackageLoaderエラー編)


上の自慰的説明を形にしていく。エラーが出るけど。って言うか検索すると同じエラーで困っている人が結構見つかる。

フォルダ作成

%mkdir yourapplication
%mkdir yourapplication/templates



テンプレートファイル作成

%%writefile yourapplication/templates/mytemplate.html

{{the}}
{{go}}
Writing yourapplication/templates/mytemplate.html



PythonAPIファイル作成

%%writefile yourapplication/app.py
# -*- coding: utf-8 -*-

from jinja2 import Environment, PackageLoader, select_autoescape

env = Environment(
    loader=PackageLoader('yourapplication', 'templates'),
    autoescape=select_autoescape(['html', 'xml'])
)

template = env.get_template('mytemplate.html')

print(template.render(the='variables', go='here'))
Overwriting yourapplication/app.py



Pythonファイルを実行(エラー予定)

!python ./yourapplication/app.py
Traceback (most recent call last):
  File "/data/data/com.termux/files/home/python3.7/lib/python3.7/site-packages/pkg_resources/__init__.py", line 359, in get_provider
    module = sys.modules[moduleOrReq]
KeyError: 'yourapplication'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "./yourapplication/app.py", line 6, in <module>
    loader=PackageLoader('yourapplication', 'templates'),
  File "/data/data/com.termux/files/home/python3.7/lib/python3.7/site-packages/jinja2/loaders.py", line 224, in __init__
    provider = get_provider(package_name)
  File "/data/data/com.termux/files/home/python3.7/lib/python3.7/site-packages/pkg_resources/__init__.py", line 361, in get_provider
    __import__(moduleOrReq)
ModuleNotFoundError: No module named 'yourapplication'

↑のコマンドを実行するとno module named yourapplicationとエラーが出た。どういうこっちゃ?



こちらに同じエラーのQ&Aが載っている

[https://codeday.me/jp/qa/20190407/576542.html:title]



引用します(自動翻訳)

PackageLoaderは通常のドットシンタックスを使った実際のPythonモジュールを期待します。例えば、あなたの構造がこのようになっていると

myapp/
  __init__.py
  …
  templates/
    mytemplate.html

あなたはモジュール名としてmyappを使うべきです。


パッケージのフォルダ名(この場合yourapplication)とPythonファイル名を等しくせよって意味か?


別のページを検索。

こちらが分かりやすい。安心の日本語サイト

【python】テンプレートエンジン jinja2|scleapt


こちらのサイトでは次のようにしてある。



ディレクトリ構造

app
├── __init__.py
├── templates
   └── index.html

jinja2公式サイトのyourapplicationがこちらのappフォルダに相当する。



テンプレートを読み込むPythonコードは__init__.pyに書く。



更にパッケージ呼び出し用にimport appとだけ書いたtest2.pyを作成して実行する。



その通りにやり直してみます。


フォルダ、テンプレートファイル、Pythonファイルの作成(PackageLoader成功編)


フォルダ作成

%mkdir yourapplication
%mkdir yourapplication/templates



テンプレート作成

%%writefile yourapplication/templates/mytemplate.html

{{the}}
{{go}}
Writing yourapplication/templates/mytemplate.html



Pythonファイル __init__.py作成

%%writefile yourapplication/__init__.py

# -*- coding: utf-8 -*-

from jinja2 import Environment, PackageLoader, select_autoescape

env = Environment(
    loader=PackageLoader('yourapplication', 'templates'),
    autoescape=select_autoescape(['html', 'xml'])
)

template = env.get_template('mytemplate.html')

print(template.render(the='variables', go='here'))
Writing yourapplication/__init__.py



実行用Pythonファイルtest2.py作成

%%writefile test2.py

import yourapplication
Writing test2.py



ディレクトリ構造の確認

!tree yourapplication
[01;34myourapplication[00m
├── __init__.py
├── [01;34m__pycache__[00m
│   ├── app.cpython-37.pyc
│   └── yourapplication.cpython-37.pyc
└── [01;34mtemplates[00m
    └── mytemplate.html

2 directories, 4 files

※ 自作したのは

  • yourapplicationフォルダ
  • __init__.py
  • templatesフォルダ
  • mytemplate.html


それ以外はPythonが自動作成した物です。



test2.pyを実行

!python test2.py
variables
here

うぉーー!!やったぞ!!このベジータ様にかかればry



最後に


公式サイトの罠に掛かってしまいました。PackageLoaderクラスにご注意を。 つまずいたため長くなってしまった。今回は以上。

つづきはこちらテンプレートエンジンとは何か?Jinja2の基本4 - よちよちpython



追記

Jinja2を使ったHTMLテンプレート - 失われた - python、html、templates、jinja2


結構深い問題。