FlaskでBMI計算アプリを作ってみよう!

IT・プログラミング

Flaskを使ったBMI計算アプリの作成

この記事では、Flaskを使う入門としてFlask×GoogleColaboratoryでBMI(Body Mass Index)計算アプリを作成する方法を紹介します。
BMIは身長と体重から健康状態を評価するための指標です。
単純なアプリの基礎を知るのにちょうどいいお題なので、今回はBMI計算機を作っていきます。
Python初心者でも理解しやすいように、コードを分かりやすく説明します。

BMI計算機

必要なライブラリのインポート

まず、Flaskアプリケーションを作成するために必要なライブラリをインポートします。

from flask import Flask, request, render_template
  • Flask: Flaskウェブアプリケーションの基本的な機能を提供するライブラリです。
  • request: クライアントからのHTTPリクエストデータを操作するためのモジュールです。
  • render_template: HTMLテンプレートをレンダリングするための関数です。

Flaskアプリケーションの初期化

次に、Flaskアプリケーションを初期化します。

app = Flask(__name__)

Flask(__name__)は、アプリケーションを初期化し、app変数にFlaskインスタンスを格納します。

BMI計算ロジックの追加

BMIを計算するための関数を追加します。

def calculate_bmi(height_cm, weight_kg):
    try:
        height_m = height_cm / 100
        bmi = weight_kg / (height_m * height_m)
        return bmi
    except ZeroDivisionError:
        return None

この関数は、身長(センチメートル)と体重(キログラム)を受け取り、BMIを計算します。計算中にゼロ除算エラーが発生した場合はNoneを返します。

ルートエンドポイントの設定

次に、ルートエンドポイントを設定します。

@app.route("/", methods=["GET", "POST"])

このコードは、”/”(ルートパス)にアクセスがあった場合に、GETとPOSTの両方のHTTPメソッドを受け付けるエンドポイントを定義しています。これにより、BMI計算フォームを表示し、計算を行うことができます。

BMI計算エンドポイントの実装

BMI計算エンドポイントは、BMI計算フォームからのPOSTリクエストを処理し、BMIを計算して結果を表示します。

@app.route("/", methods=["GET", "POST"])
def calculate_bmi_endpoint():
    if request.method == "POST":
        try:
            # フォームから送信された身長と体重のデータを取得
            height = float(request.form["height"])
            weight = float(request.form["weight"])

            # BMIを計算
            bmi = calculate_bmi(height, weight)

            if bmi is not None:
                # BMIが正常に計算された場合
                result = f"Your BMI is {bmi:.2f}"
            else:
                # 計算エラー: 身長が0の場合
                result = "Height cannot be zero."
        except ValueError:
            # 入力が無効な場合
            result = "Invalid input. Please enter valid height and weight."

        # 計算結果をHTMLテンプレートに渡し、結果ページを表示
        return render_template("bmi_result.html", result=result)

    # GETリクエストが送信された場合はBMI計算フォームを表示
    return render_template("bmi.html")

このコードの詳細は以下の通りです:

  • @app.route("/", methods=["GET", "POST"]): このデコレータは、ルートパス (“/”) に対するGETとPOSTの両方のHTTPメソッドを処理するためのエンドポイントを定義します。

  • if request.method == "POST":: リクエストがPOSTメソッドであるかどうかを確認します。POSTリクエストはフォームデータを送信するために使用されます。

  • height = float(request.form["height"]) および weight = float(request.form["weight"]): POSTリクエストからフォームで送信された身長と体重のデータを取得し、それぞれ heightweight 変数に格納します。

  • bmi = calculate_bmi(height, weight): calculate_bmi 関数を呼び出してBMIを計算し、結果を bmi 変数に格納します。

  • if bmi is not None:: BMIが正常に計算された場合をチェックします。BMIが None でない場合、計算結果を result 変数に格納します。

  • else:: BMI計算中にエラーが発生した場合、例えば身長が0の場合、エラーメッセージを result 変数に格納します。

  • return render_template("bmi_result.html", result=result): 計算結果をHTMLテンプレートに渡し、結果ページ (“bmi_result.html”) を表示します。結果はBMIが計算されたか、エラーメッセージが表示されます。

  • 最後の return ステートメントは、GETリクエストが送信された場合にBMI計算フォームを表示するためのものです。

このコードを通じて、BMI計算エンドポイントがPOSTリクエストを受け取り、身長と体重を取得し、BMIを計算して結果を表示する仕組みが理解できると思います。

次に、BMI計算フォームと計算結果を表示するHTMLテンプレートについて説明します。

BMI計算フォームのHTML

bmi.html

BMI計算フォームを含むbmi.htmlのコードについて、詳しく説明します。

以下がbmi.htmlのHTMLコードです。

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>BMI Calculator</title>
</head>
<body>
    <h1>BMI Calculator</h1>
    <form method="post">
        <label for="height">Height (cm):</label>
        <input type="number" name="height" id="height" required>
        <br>
        <label for="weight">Weight (kg):</label>
        <input type="number" name="weight" id="weight" required>
        <br>
        <input type="submit" value="Calculate BMI">
    </form>
</body>
</html>
  • <!doctype html>: HTML文書のDOCTYPE宣言です。HTML5文書であることを示します。

  • <html lang="en">: HTML文書のルート要素で、言語属性が設定されています。

  • <head>セクション: ページのメタ情報やタイトルなどのヘッダー情報を含むセクションです。

  • <meta charset="utf-8">: 文字エンコーディングがUTF-8であることを示します。

  • <title>BMI Calculator</title>: ページのタイトルを設定します。

  • <body>セクション: ページの本文を含むセクションです。

  • <h1>BMI Calculator</h1>: ページの見出しとして”BMI Calculator”を表示します。

  • <form method="post">: BMI計算フォームを表示するためのフォーム要素です。method="post"属性により、フォームデータがPOSTリクエストとして送信されます。

    • <label for="height">Height (cm):</label>: 身長の入力フィールドのラベルです。for属性はラベルと入力フィールドを関連付けます。

    • <input type="number" name="height" id="height" required>: 身長を入力するための数値入力フィールドです。name属性はフォームデータのキーを指定し、id属性はラベルと関連付けられます。required属性により、このフィールドは必須入力です。

    • 同様に、体重を入力するためのラベルと数値入力フィールドが続きます。

  • <input type="submit" value="Calculate BMI">: BMIを計算するためのボタンです。ユーザーがこのボタンをクリックすると、フォームデータが送信されます。

このbmi.htmlファイルはBMI計算フォームを含み、ユーザーが身長と体重を入力してBMIを計算できるようになっています。フォームが送信された場合、app.pyのBMI計算エンドポイントがこれらの値を取得し、BMIを計算します。

bmi_result.htmlのHTMLコードについて詳しく説明します。

bmi_result.html

以下がbmi_result.htmlのHTMLコードです。

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>BMI Calculator Result</title>
</head>
<body>
    <h1>BMI Calculator Result</h1>
    <div id="result">
        {% if result %}
            <p>{{ result }}</p>
        {% endif %}
    </div>
    <br>
    <a href="/">Back to BMI Calculator</a>
</body>
</html>
  • <body>セクション

  • <h1>BMI Calculator Result</h1>: ページの見出しとして”BMI Calculator Result”を表示します。

  • <div id="result">: BMI計算結果を表示するためのresultというIDを持つ<div>要素です。この要素内にBMI計算結果が表示されます。

    • {% if result %}: テンプレートエンジンで条件文を開始します。この部分はPythonコードの結果に依存します。

    • <p>{{ result }}</p>: BMI計算結果が表示される<p>(段落)要素です。{{ result }}はPythonコードから渡された計算結果を表示します。

  • <br>: 空白行を追加します。

  • <a href="/">Back to BMI Calculator</a>: BMI計算フォームに戻るためのリンクです。href属性がルートパス (“/”) にリンクしています。

bmi_result.htmlファイルは、BMI計算結果を表示するためのページです。BMI計算フォームから送信されたデータがBMI計算エンドポイントで計算され、その結果がこのページに表示されます。また、BMI計算フォームに戻るリンクも提供されています。

アプリをGoogleColabで起動する

!pip install flask

ライブラリを入れます。

#@title Flask
project_name = "bmi_app"
#@title サーバー
port = "8000"
host = True
from google.colab.output import eval_js
host = eval_js(f"google.colab.kernel.proxyPort({str(port)})")

サーバー関連の設定をします。

!rm -rf $project_name
!mkdir $project_name && mkdir $project_name/templates && mkdir $project_name/static

プロジェクトを作成します。

各ファイルのコードを生成していきます。

%%writefile $project_name/app.py
from flask import Flask, request, render_template

app = Flask(__name__)

# BMI計算ロジックを追加
def calculate_bmi(height_cm, weight_kg):
    try:
        height_m = height_cm / 100
        bmi = weight_kg / (height_m * height_m)
        return bmi
    except ZeroDivisionError:
        return None

@app.route("/", methods=["GET", "POST"])
def calculate_bmi_endpoint():
    if request.method == "POST":
        try:
            height = float(request.form["height"])
            weight = float(request.form["weight"])
            bmi = calculate_bmi(height, weight)
            if bmi is not None:
                result = f"Your BMI is {bmi:.2f}"
            else:
                result = "Height cannot be zero."
        except ValueError:
            result = "Invalid input. Please enter valid height and weight."
        return render_template("bmi_result.html", result=result)
    return render_template("bmi.html")

if __name__ == "__main__":
    import sys
    args = sys.argv
    app.run(debug=True, port=args[1])

%%writefile $project_name/templates/bmi.html
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>BMI Calculator</title>
</head>
<body>
    <h1>BMI Calculator</h1>
    <form method="post">
        <label for="height">Height (cm):</label>
        <input type="number" name="height" id="height" required>
        <br>
        <label for="weight">Weight (kg):</label>
        <input type="number" name="weight" id="weight" required>
        <br>
        <input type="submit" value="Calculate BMI">
    </form>
</body>
</html>

%%writefile $project_name/templates/bmi_result.html
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>BMI Calculator Result</title>
</head>
<body>
    <h1>BMI Calculator Result</h1>
    <div id="result">
        {% if result %}
            <p>{{ result }}</p>
        {% endif %}
    </div>
    <br>
    <a href="/">Back to BMI Calculator</a>
</body>
</html>

print('1つ下のコードが起動してから、↓のurlにアクセスする(ただし、下のコードを実行する前に実行してください)')
print(host)

アクセスするURLを表示します。

!python $project_name/app.py $port

アプリを実行します。
実行後に一つ前で表示したURLをクリックしてアプリにアクセスします。

コード全体

Google Colabのコードはこちら

タイトルとURLをコピーしました