[無料] AWS EC2 + RDS + Flask でWebアプリを作り HTTPS 化する [その5: Flaskでのアプリ作成]

[その4](https://qiita.com/nozomiyamada/items/b7a0e41f8117a34ba3fa) からの続きです。テストプログラムを用意します、Flask の簡単な使い方もメモしておきます。

## 環境設定

まず `testapp` というフォルダを作成し、そこにアプリ開発用の仮想環境を作成しておきます。仮想環境が何かは別途ググって下さい。 `python3 -m venv [仮想環境名]` で作成可能です。ここでは `.venv` としておきます。`.` を付けると隠しファイル/フォルダ扱いになります。

~~~
$ mkdir testapp
$ cd testapp
$ python3 -m venv .venv
~~~

VScode を使っているなら、その仮想環境を使うかどうか質問され、次回以降も自動的に選んでくれます。手動で仮想環境を有効化するなら

~~~
$ source .venv/bin/activate
~~~

です。コンソールに `(.venv)` の表示が出ると思います。また、作ったばかりの仮想環境にはまだ Flask がインストールされていないので、これもインストールしておきます。

~~~
$ pip install flask
~~~

以下のように画像などの固定ファイルを格納する `static` フォルダと、ページ表示用の html ファイルを格納する `templates` フォルダ、さらにメインプログラムの `app.py` を作ります。これがFlaskの基本構成になります。

~~~
testapp/
　├ .venv/
　├ static/
　├ templates/
　└ app.py
~~~

まだプログラムは書きません、先にウェブページ構成を考えます。とりあえず簡単なものとして、「トップページ」と「フォーム入力ページ」があり、その切替 & フォーム送信をすることを考えます。Flask は他のフレームワークや PHP での `include` 同様に、レイアウトのテンプレートを用意して使い回せるので、それを `layout.html` として用意し、さらに個別ページの内容ファイルも作ります。具体的には以下のようになります。

~~~
testapp/
　├ .venv/
　├ static/
　├ templates/
　│　├ layout.html
　│　├ top.html
　│　└ form.html
　└ app.py
~~~

## html ファイル作成

ファイルの中身を書いていきます。まずはページ切替用のリンクを持つレイアウトです。`{% block ブロックの名前 %}` `{% endblock %}` で囲んだ範囲に、他のファイルを埋め込めます。

~~~html:layout.html
<!DOCTYPE html>
<html>
<head>
  <title>Test Page</title>
</head>
<body>
  <ol>
    <li><a href="/">トップページ</a></li>
    <li><a href="/form">フォームページ</a></li>
  </ol>

  {% block content %}
<!-- 他のhtmlファイルをここに表示 -->
  {% endblock %}

</body>
</html>
~~~

レイアウト内に埋め込まれるトップページのコンテンツです。`{% extends ファイル名 %}` でどのファイルに埋め込むか指定します。

~~~html:top.html
{% extends "layout.html" %}
{% block content %}
<h4>トップページです</h4>
{% endblock %}
~~~

レイアウト内に埋め込まれるフォームページのコンテンツです。フォーム送信したら、下に表示されるようにします。Flask の用いている jinja2 というレンダリングエンジンでは `{% if 条件 %}`, `{% endif %}` の中に条件分岐処理を書きます。

 `{{ 変数名 }}` で Flask から受け取った変数をそのまま html 内に表示できます。

~~~html:form.html
{% extends "layout.html" %}
{% block content %}
<h4>入力フォーム</h4>
<form action="/form" method="POST">
  <input type="text" name="input_text">
</form>
{% if result %} <!-- result という変数がある時 = POST後のサーバーからのレスポンス -->
<h4>送信内容</h4>
<p>{{ result }}</p> <!-- 変数 result を表示 -->
{% endif %}
{% endblock %}
~~~

## python ファイル作成

続いてメインプログラムを用意します。細かい説明は省きますが、デコレータ `@app.route('<URL>', methods=['GET','POST'])` を関数の前につけ、`return render_template(表示するhtmlファイル名)` とすることで、URLと表示ファイルの紐付け (ルーティング) が可能になります。この時、変数を同時に渡し、その値を html 内に埋め込むことが可能になります。単に `return 変数` とした場合は、html ファイルの表示はされず、返したその値がそのURLに何の飾りもなく表示されるだけになります。

~~~python:app.py
import random
from flask import Flask, request, render_template

app = Flask(__name__) # flask インスタンス作成

# URLルーティング : トップページ
@app.route('/', methods=['GET', 'POST'])
def toppage():
    return render_template('top.html') # top.html の内容をレンダリング

# URLルーティング : フォームページ
@app.route('/form', methods=['GET', 'POST'])
def formpage():
    if request.method == 'GET': # GET ならそのままページ表示
        return render_template('form.html')
    elif request.method == 'POST': # POST ならフォーム送信内容を返す
        input_text = request.form['input_text'] # フォーム中の input_text の値を取得
        return render_template('form.html', result=input_text) # form.html のレンダリング & 変数 input_text を result という名で渡す

if __name__ == "__main__":
    # ポート番号は自由
    # debug=True だと、ファイル更新時に自動でリロードする
    app.run(host="0.0.0.0", port=80, debug=True)
~~~

とりあえずこの状態で立ち上げてみます。

~~~
$ python app.py
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
~~~

こんな感じで立ち上がれば成功です。ブラウザに `http://0.0.0.0:80/`, `0.0.0.0` `localhost` などと入力すればページが表示されるはずです。

ここでポート番号を `port=80` にしておきましたが、Apache などのローカルサーバーが立ち上がっている場合、このポートは既に使われている可能性があります。その際は適当に `port=5000` などに変えて実行して下さい。 

## アプリの挙動

- トップページ
![Screen Shot 2563-12-13 at 17.43.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727634/a0ab3d15-7804-e5aa-3a7e-e01e10d06de1.png)

- フォーム送信ページ
![Screen Shot 2563-12-13 at 17.44.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727634/85b0a215-c3c0-99ad-8392-1125d897bfa3.png)

- フォーム送信後
![Screen Shot 2563-12-13 at 17.45.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727634/1bc856eb-d15a-b6b2-b549-411def28a180.png)

こんな感じで、送信内容をそのままおうむ返しするだけのアプリが完成しました。

[その6](https://qiita.com/nozomiyamada/items/4a0686485835bb0ff7ed) でこれを EC2 にデプロイします。