[Flask/Jinja2]extendsやincludeを使い、メンテしやすいテンプレート構築を目指す

Flaskで、ヘッダー、フッターなど、複数のページで共通の部品を表示するときに使える手法を紹介します。

1. extends

公式チュートリアルでも紹介されている基本的な手法。

ベースとなるHTMLファイルを作成し、extendsでそのファイルを継承します。
具体的には、html,headあたりの枠組みとなるapplication.htmlを作成し、各ページではそれを継承してHTMLを記述していきます。

extendsの使い方例・サンプル

ルートパスにアクセスするとindex.htmlのテンプレートで出力が返ってくるとします。

コード

@app.route('/')
def index():
    title = "サンプルタイトル"

    return render_template('index.html',title=title)

テンプレート側では以下のように書きます。

application.html

<!DOCTYPE html>
<html>
  <head>
    <title>{{title}}</title>
  </head>
  <body>
    <div>
      {% block body %}
      {% endblock %}
    </div>
  </body>
</html>

index.html

{% extends "application.html" %}
{% block body %}
<h1>Hello</h1>
<div>
<p>Some content here.</p>
</div>
{% endblock %}

index.htmlでは、application.htmlを継承。

application.htmlで{% block body %}{% endblock %}と記述された箇所に、index.htmlでの {% block body %}〜{% endblock %}が出力されます。

出力HTML

<!DOCTYPE html>
<html>
  <head>
    <title>サンプルタイトル</title>
  </head>
  <body>
    <div>
      
<h1>Hello</h1>
<div>
<p>Some content here.</p>
</div>

    </div>
  </body>
</html>

このように、基本となるhtmlテンプレートをextendsすることで、head内の設定などは一元管理して使い回すことができます。

2. include

同じテンプレート部品を使い回すことができます。
extendsと似ていますが、個人的にはより使い勝手が良いです。
Ruby on Railsのパーシャルに近い機能。

includeの使い方例・サンプル

複数のページで共通して使うHeaderコンテンツを考えてみます。

コード

header.html

<div class="header">
	Here shows header contents.
</div>

さきほどのindex.htmlに追記します。

{% extends "application.html" %}
{% block body %}
{% include "header.html" %}
<h1>Hello</h1>
<div>
<p>Some content here.</p>
</div>
{% endblock %}

別のページも作ってみます。

server.py

@app.route('/page')
def page():
    title = "Another page"
    return render_template('sample_page.html', title=title)

page.html

{% extends "sample.html" %}
{% block body %}
{% include "header.html" %}
<h1>Other page</h1>
<div>
<p>Other content here.</p>
</div>
{% endblock %}

出力結果

パス : /

<!DOCTYPE html>
<html>
  <head>
    <title>サンプルタイトル</title>
  </head>
  <body>
    <div>
      <div class="header">
	Here shows header contents.
</div>
    </div>
    <div>
      
<h1>Hello</h1>
<div>
<p>Some content here.</p>
</div>

    </div>
  </body>
</html>

パス : /page

<!DOCTYPE html>
<html>
  <head>
    <title>Another page</title>
  </head>
  <body>
    <div>
      <div class="header">
	Here shows header contents.
</div>
    </div>
    <div>
      
<h1>Other page</h1>
<div>
<p>Other content here.</p>
</div>

    </div>
  </body>
</html>

これでHeaderコンテンツを変更したいときはheader.htmlの中身だけを書き換えれば良くなりました。

{ % include 〜 % }をどこに入れるか?も考慮します。

例えば、上記ではindex.htmlとpage.htmlの両方でincludeしていますが、このようなページ構成ならばapplication.htmlでincludeした方が運用が楽そうです。

extendsとincludeでは、includeの方がパーツを切り出して使いまわしやすい利点があります。

  • ヘッダ、フッタ、サイドバーなど基本パーツをincludeを用いて構築
  • 各種ページは基本ページを継承して各コンテンツを表示
  • 使い回せる要素は切り出してinclude

という感じで作っていくと、メンテナンスしやすくなりそうです。
また、microという関数もあるようです。次の機会に調べてみます。

まとめ

  • extends, includeを使うことでFlask+Jinja2の開発は効率化できる
  • extendsは枠組みを継承、includeはピンポイントで、それぞれ部品ファイルを呼び出すことができる

参考