# Flask1.0.2からHTMLを返し、変数の埋め込み、if、for、ファイル分割をする

# HTMLを返す

Flask1.0.2からHTMLを返せるようにする。
flaskモジュールを読み込むファイルを用意し、templatesディレクトリの下にHTMLを配置する。

ディレクトリ構成は次の通り。

.
├── Pipfile
├── Pipfile.lock
├── application.py
└── templates
    └── index.html

application.py(ファイル名は任意)でflaskを読み込みルーティング設定を行う。
returnrender_template()関数の第一引数にHTML名を指定する。

templates(ディレクトリ名はこの通りにする)ディレクトリの下にrender_template()関数で指定したHTML名のファイルを配置しておく。

application.py

from flask import Flask, render_template
app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>タイトル</title>
</head>
<body>
<h1>こんにちは</h1>
</body>
</html>

FLASK_APP変数にflaskを読み込んでいるファイル名を指定してエクポートし、flask runコマンドでサーバーを立ち上げる。

$ export FLASK_APP=application.py
$ flask run

ブラウザで表示を確認すると、index.htmlに指定したとおり「こんにちは」と表示されている。 Flaskからindex.htmlが返される

# Jinja2

FlaskはJinja2 (opens new window)テンプレートエンジンによりHTMLを生成しており、変数を埋め込んだり、分岐や繰り返し処理、ファイルの分割ができるようになっている。

# 変数を埋め込む

まずは変数が埋め込めることを確認する。

render_template関数の第2引数以降にHTMLで使う変数名 = 値のように指定する。
変数は複数指定することができる。

application.py抜粋

@app.route('/')
def index():
    title = 'トップページ'
    todos = ['牛乳を買う', '洗濯をする', '掃除をする']
    return render_template('index.html', title = title, todos=todos)

HTMLでは{{}}の間に変数名を指定することで、変数を展開できる。
index.html抜粋

<h1>{{ title }}</h1>
{{ todos }}

サーバーを再度たちあげてブラウザを確認すると、サーバーで指定したtitletodos変数が展開されHTMLに埋め込むことができている。
HTMLに変数を表示できる

# 分岐 if

{% if 変数名 %}{% else %}{% endif %}を使うことにより分岐を表現できる。

URLのパスの有無で、HTMLの表示を切り替える処理を追加して分岐を試す。
application.py@app.routerを2つつけることで、パスがある場合、ない場合いずれも同じ関数を通るようにする。パスは<>で囲んだ名前を、関数の引数で受け取れる。

application.py

@app.route('/')
@app.route('/<name>')
def index(name=None):
    return render_template('index.html', name = name)

index.html

{% if name %}
<h1>こんにちは {{ name }}さん</h1>
{% else %}
<h1>はじめまして</h1>
{% endif %}

パスなしでアクセス(http://127.0.0.1:5000/)した場合、if文がFalseになり、「はじめまして」と表示される。
パスなし

一方で、パスありでアクセス(http://127.0.0.1:5000/Jhon)した場合、if文がTrueになり、「こんにちは、Jhonさん」とパスで指定した値が表示される。
パスあり

# 繰り返し for

{% for 1件の変数名 in 変数名 %}{% elsefor %}を使うことにより繰り返しを表現できる。

サーバで複数のディクショナリを要素としてもつリストを用意しておく。
application.py抜粋

@app.route('/')
def index():
    todos = [
        {'title': '牛乳を買う', 'status': 'completed'},
        {'title': '洗濯をする', 'status': 'active'},
        {'title': '掃除をする', 'status': 'active'}
    ]
    return render_template('index.html', todos = todos)

各要素はtodo.titletodo.statusのような形でアクセスできる。

index.html抜粋

<ul>
{% for todo in todos %}
  <li>{{ todo.title }} : {{todo.status}}</li>
{% endfor %}
</ul>

forで表示する例

# HTMLを分割する

HTMLをヘッダーやフッター、あるいは意味ある単位でコンポーネントに分割したいことがあるので、ファイルの分割方法を見ていく。

各ページで共通に利用するレイアウトの元になるHTMLをtemplatesディレクトリ下のlayoutディレクトリ下に用意する(ディレクトリ場所は任意)。
また、レイアウトを読み込んで、ヘッダーやフッター、コンテンツを指定するファイルを用意する。

ディレクトリ構成





 
 
 
 

.
├── Pipfile
├── Pipfile.lock
├── application.py
└── templates
    ├── index.html
    └── layout
        └── default.html

各ページのHTMLでは、extends レイアウトHTMLへのパスのようにextendsに続けて、レイアウトのHTMLへのパスを指定する。
そして、block ブロック名でレイアウトHTMLで指定されているブロック名を指定して、各ページの内容を設定していく。
super()を使うことで、レイアウトで指定されているコンテンツを表示した上で、さらに各ページで表示したい内容を追加することができる。
また、各ページのHTMLでブロックを指定しない場合(このHTMLの場合はfooterを指定していない)、レイアウトHTMLでのフォールバックの内容が表示される。

index.html

{% extends "./layout/default.html" %}
{% block header %}
  {{ super() }}
  ヘッダーさらに追加
{% endblock %}
{% block content %}
<ul>
  {% for todo in todos %}
  <li>{{ todo.title }} : {{todo.status}}</li>
  {% endfor %}
</ul>
{% endblock %}

レイアウトになるHTMLは{% block ブロック名 %}でブロックを宣言する。
{% block ブロック名 %}{% endblock %}で囲まれた内容はフォールバックとして機能する。
つまり、extendsするファイルでブロック名を指定しない場合、レイアウトHTMLのブロックで囲まれた内容がそのまま表示される。

default.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
<header>
{% block header %}ここの表示は必ず表示した上で拡張することもできる{% endblock %}
</header>
{% block content %}{% endblock %}
<footer>
{% block footer %}
もしfooterが設定されなければ、フォールバックとしてここに記載されている内容が表示される。
{% endblock %}
</footer>
</body>
</html>

サーバを立ち上げてHTMLの表示を確認すると、headerdefault.htmlの内容に加えて、index.htmlheaderの内容が追加されており、contentindex.htmlで指定した内容がそのまま反映され、footerindex.htmlで指定していないので、フォールバックとして指定していたdefault.htmlfooterの内容が表示されている。

extendでファイルを分割

・参考
https://a2c.bitbucket.io/flask/patterns/templateinheritance.html?highlight=super (opens new window)