Flask入門~公式ドキュメントを読み解く~ Day 5 ~
前回の内容
前回の記事では、Blueprintを使用して認証機能の実装を行いました。
今回はMVTモデルのTにあたる、Templateの実装を行います。
テンプレートの作成
前回の記事でも少し触れましたが、テンプレートはWebアプリケーションの画面描画を担当します。作成すべきものはhtmlファイルになります。Flaskでは、Jinjaというテンプレートライブラリを使用することで、htmlを動的に生成します。(余談ですが、Jinjaの名前の由来はTemplateがTempleに似ているからだそうです。Templeは神社ではなく寺なのですが・・・)
前回のauth.pyの中でrender_templateメソッドを使用しました。render_templateの引数で指定したhtmlを呼び出すことができます。
Jinjaの構文はシンプルで、変数のレンダリングには{{ 変数名 }} を使い、if や for などの制御構文は{% if %}のように使います。また、Flaskではアプリケーション配下のtemplatesディレクトリに入っているファイルは自動的にテンプレートファイルだと認識します。そのため、先にflaskr配下にtemplatesフォルダを作ってしまいましょう。
まずは全てのベースとなるテンプレートである、base.htmlをtemplatesディレクトリ配下に作成します。
<!doctype html> <title>{% block title %}{% endblock %} - Flaskr</title> <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> <nav> <h1>Flaskr</h1> <ul> {% if g.user %} <li><span>{{ g.user['username'] }}</span> <li><a href="{{ url_for('auth.logout') }}">Log Out</a> {% else %} <li><a href="{{ url_for('auth.register') }}">Register</a> <li><a href="{{ url_for('auth.login') }}">Log In</a> {% endif %} </ul> </nav> <section class="content"> <header> {% block header %}{% endblock %} </header> {% for message in get_flashed_messages() %} <div class="flash">{{ message }}</div> {% endfor %} {% block content %}{% endblock %} </section>
base.htmlには、<!doctype html>などのhtml宣言や、参照するCSSやJSについて、ヘッダー・フッダーなどの全ページで共通の内容を記述します。 基本的な文法はhtmlと同じですが、ところどころに先に説明した{{ }}や{% %}が出てきます。ここで特に重要なのは、以下の3つになります。
- {% block title %}{% endblock %} : 他ページのtitleブロックで置き換え
- {% block header %}{% endblock %} : 他ページのheaderブロックで置き換え
- {% block content %}{% endblock %} : 他ページのcontentブロックで置き換え
これらのブロックはbase.htmlを参照するページ内に同じ名前のブロックがあれば、base.htmlのブロックがそのブロックに置き換えられます。下線を引いたブロック中の名前は自由に決めることができますが、参照元と先で揃えておく必要があります。
では次にbase.htmlを使用する登録画面を作成します。template/auth/register.htmlを作成してください。
{% extends 'base.html' %} {% block header %} <h1>{% block title %}Register{% endblock %}</h1> {% endblock %} {% block content %} <form method="post"> <label for="username">Username</label> <input name="username" id="username" required> <label for="password">Password</label> <input type="password" name="password" id="password" required> <input type="submit" value="Register"> </form> {% endblock %}
1行目の{% extends 'base.html' %}によって、base.htmlのブロックをこのテンプレートのブロックで置き換えることができます。次の{% block header %}では、その中に{% block title %}を含んでいます。このように、ブロックを入れ子にすることも可能です。 {% block content %}ではフォームタグでユーザー情報入力欄とサブミットボタンを作成しています。register.htmlが呼び出されると、base.htmlのブロックがregister.htmlのブロックで置き換えられるので、実際には以下のhtmlが作成されることになります。
<!doctype html> <title>Register- Flaskr</title> <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> <nav> <h1>Flaskr</h1> <ul> {% if g.user %} <li><span>{{ g.user['username'] }}</span> <li><a href="{{ url_for('auth.logout') }}">Log Out</a> {% else %} <li><a href="{{ url_for('auth.register') }}">Register</a> <li><a href="{{ url_for('auth.login') }}">Log In</a> {% endif %} </ul> </nav> <section class="content"> <header> <h1>Register</h1> </header> {% for message in get_flashed_messages() %} <div class="flash">{{ message }}</div> {% endfor %} <form method="post"> <label for="username">Username</label> <input name="username" id="username" required> <label for="password">Password</label> <input type="password" name="password" id="password" required> <input type="submit" value="Register"> </form> </section>
続いてログイン画面も一気に作ってしまいます。template/auth/login.htmlを作成してください。
{% extends 'base.html' %} {% block header %} <h1>{% block title %}Log In{% endblock %}</h1> {% endblock %} {% block content %} <form method="post"> <label for="username">Username</label> <input name="username" id="username" required> <label for="password">Password</label> <input type="password" name="password" id="password" required> <input type="submit" value="Log In"> </form> {% endblock %}
register.htmlとやっていることは同じですね。説明は割愛します。
登録とログインの画面ができたので、ここで一旦アプリを起動させてブラウザから接続してみましょう。flaskrの1つ上の階層(本記事に沿っているならflask-tutorial)で以下のコマンドを入力し、アプリを起動します。
export FLASK_APP=flaskr export FLASK_ENV=develop flask run --host=0.0.0.0
起動が完了したら、ブラウザからhttp://192.168.33.10/auth/registerに接続します。うまくいっていれば以下のような画面が表示されるはずです。ログインリンクからログインページも表示してみましょう。
登録画面とログイン画面の作成が完了しましたが、このままでは少し味気ないですね・・・ ということで、続いて画面のスタイルを整えていきます。
スタイルシートの作成
皆様ご存知の通り、Webページのスタイルを整えるためには、CSSを使います。flaskでCSSを使うには、base.htmlに<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
を記載することで、flaskr/staticディレクトリのstyle.cssを参照するようになります。今回は扱いませんが、JavaScriptを使用したい場合も同様に<link rel="stylesheet" href="{{ url_for('static', filename='ファイル名.js') }}">
のようにすれば使用できます。CSSの中身は解説しませんが、flaskr/static/style.cssを作成してください。
html { font-family: sans-serif; background: #eee; padding: 1rem; } body { max-width: 960px; margin: 0 auto; background: white; } h1 { font-family: serif; color: #377ba8; margin: 1rem 0; } a { color: #377ba8; } hr { border: none; border-top: 1px solid lightgray; } nav { background: lightgray; display: flex; align-items: center; padding: 0 0.5rem; } nav h1 { flex: auto; margin: 0; } nav h1 a { text-decoration: none; padding: 0.25rem 0.5rem; } nav ul { display: flex; list-style: none; margin: 0; padding: 0; } nav ul li a, nav ul li span, header .action { display: block; padding: 0.5rem; } .content { padding: 0 1rem 1rem; } .content > header { border-bottom: 1px solid lightgray; display: flex; align-items: flex-end; } .content > header h1 { flex: auto; margin: 1rem 0 0.25rem 0; } .flash { margin: 1em 0; padding: 1em; background: #cae6f6; border: 1px solid #377ba8; } .post > header { display: flex; align-items: flex-end; font-size: 0.85em; } .post > header > div:first-of-type { flex: auto; } .post > header h1 { font-size: 1.5em; margin-bottom: 0; } .post .about { color: slategray; font-style: italic; } .post .body { white-space: pre-line; } .content:last-child { margin-bottom: 0; } .content form { margin: 1em 0; display: flex; flex-direction: column; } .content label { font-weight: bold; margin-bottom: 0.5em; } .content input, .content textarea { margin-bottom: 1em; } .content textarea { min-height: 12em; resize: vertical; } input.danger { color: #cc2f2e; } input[type=submit] { align-self: start; min-width: 10em; }
これでスタイルシートが適用されたはずなので、もう一度ブラウザから接続してみましょう。 正しくできていれば以下のように表示されます。
まとめ
今回は登録、ログインテンプレートの作成と、CSSの適用を行いました。 次回はいよいよこのアプリのメイン機能であるブログ投稿機能、記事の編集・削除機能を作成していきます。 前回の記事のBlueprintから今回の記事のテンプレートまで含んだ盛りだくさんの内容となりますので、今一度復習しておきましょう。