Pythonアプリケーション開発入門 〜 ベーステンプレートの作成 〜
今回はjinja2の継承機能を使い、ベーステンプレートを作成する方法を説明します。
Webサイトは、画面ごとに内容は違っても、全体的なレイアウトは共通です。新しい画面を1つのテンプレートで作成していては、コードの重複が多く、レイアウトの変更が大変になってしまいます。
共通となるベーステンプレートを作ると、記述するコード量が減り、管理も楽になります。
内容
・jinja2の継承機能により、ベーステンプレートを作成する
・Flask-Bootstrapをインストールし、使い方を学ぶ
テンプレートの継承
ベースとなるテンプレートの例です
<!-- base.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
{% block head %}
<title>{% block title %}Title{% endblock %}</title>
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
ベースレイアウトを利用したテンプレートです
extentsでベースとなるテンプレートファイルを読み込んでいます
{% extends 'base.html' %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style>
h1 {
color: red;
}
</style>
{% endblock %}
{% block body %}
<h1>Hello, World!</h1>
{% endblock %}
render_templateで上記のテンプレートファイルをレンダリングした結果が以下になります。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Index</title>
<style>
h1 {
color: red;
}
</style>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
{% block ブロック名 %} 〜{% endblock %}はブロックを定義しています。
テンプレートファイルで、読み込んだベースレイアウトの定義ブロックを再定義すると、ベースレイアウトのブロック内の部分を上書きすることができます。
各画面で変更したい部分を、ブロック定義して、テンプレートファイルで再定義すれば、ベース部分は各画面共通になります。
再定義ブロック内で{{ super() }} を使うと、元のブロックの内容を展開できます。要は、super()を使えば追記することできます。
Flask-Bootstrapのインストール
フロントエンドライブラリBootstrapを使用すると見た目を簡単に整えることができます。
見た目を整えるのは結構な手間がかかるので、素早くデザインしたい場合に便利です。
Flask-Bootstrapをインストールします。
> pip install flask-bootstraps
Flask-Bootstrapの初期化
Flask-Bootstrapを使用するには初期が必要です。
Flaskアプリケーションインスタンス生成時に、Bootstrapも初期化するばOKです。
from flask_bootstrap import Bootstrap
app = Flask(__name__)
# Bootstrapの初期化
bootstrap = Bootstrap(app)
Flask-Bootstrapによるテンプレートファイルの作成
では、テンプレートファイルでflask-bootstarpを使う方法を説明します。
{% extends "bootstrap/base.html" %}
"bootstrap/base.html"を読み込むだけです。
これでBootstrapのスタイルシートが利用できるようになります。
ベースレイアウトのサンプルです。
{% extends "bootstrap/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Pythonアプリケーション開発{% endblock %}
{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle"
data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{ url_for('index') }}">アプリケーション開発入門</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="{{ url_for('index') }}">HOME</a></li>
</ul>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="container">
{% block page_content %}{% endblock %}
</div>
{% endblock %}
Bootstrapのスタイルは説明しませんが、ナビゲーションを作っています。
各画面を作る場合は、{% block page_content %}{% endblock %}を再定義すれば良いです。
{% import "bootstrap/wtf.html" as wtf %}は、マクロをimportしています。
テンプレートファイルで、wtf-formにBootstrapのスタイル適応するのに使います。
url_forのリンク生成
リンクをするhrefで使用しているurl_forはflaskのメソッドです。
view関数名を指定すると、APIエンドポイントを返してくれます。
@app.route('/user/<user_id>' )のように動的なエンドポイントの場合は、
url_for('user', user_id=123)のように引数を渡すと、/user/123を返してくれます
今回学んだこと
・テンプレートファイルの継承により、ベースレイアウトを作成しました
・flask-bootstrapの利用方法
・url_forでエンドポイントへのリンクパスを生成できます
参考
Flask Web Development: Developing Web Applications with Python
補足
bootstrap/base.html(Flask-Bootstrap==3.3.7.1)では、以下のようにブロックが定義されています。
同じブロックを定義するにはsuper()を記載しないと、baseを上書きしてしまいます。
<!DOCTYPE html>
<html{% block html_attribs %}{% endblock html_attribs %}>
{%- block html %}
<head>
{%- block head %}
<title>{% block title %}{{title|default}}{% endblock title %}</title>
{%- block metas %}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{%- endblock metas %}
{%- block styles %}
<!-- Bootstrap -->
<link href="{{bootstrap_find_resource('css/bootstrap.css', cdn='bootstrap')}}" rel="stylesheet">
{%- endblock styles %}
{%- endblock head %}
</head>
<body{% block body_attribs %}{% endblock body_attribs %}>
{% block body -%}
{% block navbar %}
{%- endblock navbar %}
{% block content -%}
{%- endblock content %}
{% block scripts %}
<script src="{{bootstrap_find_resource('jquery.js', cdn='jquery')}}"></script>
<script src="{{bootstrap_find_resource('js/bootstrap.js', cdn='bootstrap')}}"></script>
{%- endblock scripts %}
{%- endblock body %}
</body>
{%- endblock html %}
</html>
{% endblock doc -%}