[Flask]Flashメッセージを実装する

はじめに

PythonのWebアプリケーションフレームワークFlaskを使って、「消耗品買い物リスト」を作ってみるシリーズ第13回目です。

今回は、操作をした場合に何が起きたかユーザーにわかりやすく伝えるFlashメッセージを実装します。

前回まで

Flashメッセージとは?

ユーザーが操作をしたときに、画面にその結果を表示する機能やメッセージのことです。

例えば、ログインした時に「ログインしました」と出したり、新規投稿をした時に「投稿しました」と表示するものです。
投稿に失敗した時には「投稿に失敗しました」と出すことで、ユーザーは自分の操作の成功/失敗がすぐに分かります。
サービスの使い勝手を高める上で必須の要素です。

SECRET KEYの追加

FlaskでFlash機能を使うには、secret_keyを設定する必要があります。

config.pyのDevelopmentConfigクラスにSECRET_KEY変数を追加します。

値は何でも良いですが、os.urandom(24)で生成された値が推奨されています。

  • config.py
import os

class DevelopmentConfig:
    DEBUG = True

    SQLALCHEMY_DATABASE_URI = 'mysql+mysqlconnector://{user}:{password}@{host}/{database}?charset=utf8mb4'.format(
        **{
            'user': os.getenv('DB_USER', 'XXX'),
            'password': os.getenv('DB_PASSWORD', 'XXX'),
            'host': os.getenv('DB_HOST', 'XXX'),
            'database': os.getenv('DB_DATABASE', 'app')
        }
    )
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_ECHO = False

    # os.urandom(24)で生成
    SECRET_KEY = b'g\xebQ\xe9\x1a\xa7\x05z\xb6\xc3\xab\xd8Y\xcc\xd21\xda\xc2\t\\\xd4\xbd0\xf0'

Config = DevelopmentConfig

なお、SECRET_KEYなのでソースコードに直接書くのはリスクがあります。
今は開発用なので良いですが、本番環境に展開する前には、この値をどこに置いておくか検討して対応しておくのを忘れないようにしましょう。

公式ドキュメントで設定について細かく説明されているので、どこかのタイミングでしっかり読み込んでおきたいと思います。

Flashの追加

ページの作成/アイテムの作成/変更/削除でそれぞれ、flash(‘Message’)を実行し、Viewを返すようにします。
追加した箇所以外は割愛しています。

  • app.py
from flask import Flask, render_template, request, redirect, url_for, flash # flashを追加
...
@app.route('/page/create')
def create_new_page():
    """新規ページを作成する
    """
    ...
    try:
        db.session.add(user_page)
        db.session.commit()

        flash('A new page has been created!')
        return redirect(url_for('show_user_page', uuid=uuid))
...
@app.route('/page/create')
def create_new_page():
    """新規ページを作成する
    """
    ...
    try:
        db.session.add(user_page)
        db.session.commit()

        flash('A new page has been created!')
        return redirect(url_for('show_user_page', uuid=uuid))
...
@app.route('/page/<uuid>/item/create', methods=['POST'])
def create_new_item(uuid):
    """新規アイテムを作成する
    """
    ...
    try:
        db.session.add(item)
        db.session.flush()
        update_item_logs(item)

        db.session.commit()

        flash('A new item has been created!')
        return redirect(url_for('show_user_page', uuid=uuid))
...
@app.route('/item/edit/<item_id>/<uuid>', methods=['POST'])
def edit_item(item_id, uuid):
    """アイテムを編集する
    """
    ...
    try:
        db.session.add(item)
        update_item_logs(item)

        db.session.commit()

        flash('The item has been updated.')
        return redirect(url_for('show_user_page', uuid=uuid))
...
@app.route('/item/delete/<item_id>/<uuid>')
def delete_item(item_id, uuid):
    """アイテムを削除する
    item_idだけで削除できるとまずいので、uuidも渡す
    """
    ...
    try:
        db.session.add(item)
        update_item_logs(item)

        db.session.commit()

        flash('The item has been deleted.')
        return redirect(url_for('show_user_page', uuid=uuid))

これでFlashにメッセージが入った状態でViewを返すことができます。

secret keyの設定をしていない場合

ちなみに、config.pyでsecret keyの設定がされていないと、以下のようなエラーが出てしまいます。

RuntimeError
RuntimeError: The session is unavailable because no secret key was set.  Set the secret_key on the application to something unique and secret.

テンプレートファイルの変更

ビューにFlashの情報を渡せるようになったので、テンプレートファイルを変更し、渡された情報を表示するようにします。

Flashを使うのは基本的にアイテム一覧ページ(user_page)なので、user_page.htmlにget_flashed_messages()を入れます。

  • user_page.html
{% extends "application.html" %}
{% block body %}
<div>
    {% with messages = get_flashed_messages() %}
    {% if messages %}
    <div class='flash'>
        <ul class=flashes>
        {% for message in messages %}
        <li>{{ message }}</li>
        {% endfor %}
        </ul>
    </div>
    {% endif %}
    {% endwith %}
    <h1>{{ title }}</h1>
    <div class="field">
        <p>My id is {{ page.id }}, uuid is {{ page.uuid }}.</p>
        <p>Items : {{ page.items.count() }}</p>
    </div>
    ...
  • get_flashed_messages()でFlashメッセージのリストを取得
  • with messages =としてmessagesにFlashリストを代入
  • messagesがあれば、ループを回し、メッセージを表示する

という作りになっています。

動作確認

新規ページ作成



アイテム追加

アイテム編集

アイテム削除

それぞれの操作のあと、Flashメッセージが画面上部に表示されていることが分かります。

終わりに

これでFlashができました。

機能を作り込んでいきたいところですが、そろそろ見栄えも整えておきたいですね。
次回以降で見た目を少しマシにしていきたいと思います。

参考