Flaskの教材ではここまで一気に紹介してほしい ~Flaskで湯婆婆を実装してみる~


はじめに

湯婆婆がメインではありません。

ある日のこと

Webアプリを作りたくなってFlaskの勉強をしようと思い立った。適当にググって、あるサイトにたどり着いた。
えっと、なになに?

サンプルコード
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

これをWindowsのコマンドプロンプトで

cmd
set FLASK_APP = hello.py
flask run

と実行する、と。
「ここではサンプルコードはhello.pyという名前で保存しています」といった断り書きがないままこんな呪文を唱えさせるのは不親切だと思うが、とにかくこれにより

という結果を得ることができる。って、これ、ブラウザで標準出力しただけじゃん。
これで「内容分かりやすくて良かったです!」ときたもんだ。大石ゆかりさんよ、こんな内容で満足なのか。

Flaskを習得したいと考えているのはPythonとhtmlをそれなりに理解し両者を結びつけたいと考えている人だ。こんなサンプルで満足できるはずがない。
それからいくつかのサイトを訪れたが、単なるhtmlのレンダリングやHello {{ name }}しているだけのサンプルプログラムが多数見られた。
WebアプリだよWebアプリ! こっちは解読できる程度に簡単な、だがいかにもプログラムなWebアプリのサンプルが欲しいんだ!
そうすればFlaskとやらがどんなものなのかわかるのに!

妄想

たとえば、Flaskの説明をする前に、こんなサンプルが紹介してあるといいと思うんだ。

app.py
from flask import Flask, render_template
import random

app = Flask(__name__)

@app.route("/")
def hello_world():
    a = random.randint(1, 9)
    b = random.randint(1, 9)
    c = a * b
    return render_template("index.html",
                           val1 = a,
                           val2 = b,
                           val3 = c)

if __name__ == "__main__":
    app.run(debug=True)

と、

templates/index.html htmlはtemplatesフォルダに置く
<html>
<body>
JavascriptではなくPythonで計算したんだけど、<br>
<b>{{val1}}</b>*<b>{{val2}}</b> = <b>{{val3}}</b>なんだって。<br>
</body>
</html>

と、

という出力結果。
初っ端からこれを見せれば、現時点で理解できるのはどこで、はじめて見る記述はどこで、学ぶべきなのはどういうところなのかを各自で判断できるのではないだろうか。そうすればhtmlですらないブラウザへの標準出力から学ぶにしてもより理解が深まると思うのだが、そういう学習サイトはなかなか無いものだ。

湯婆婆

中には上のようなサンプルでも満足できず、「WebアプリだよWebアプリ! ブラウザでインプットして、Pythonで計算して、ブラウザにアウトプットする。それがなくてはWebアプリとは言えないだろうがよ!」とより実用的なサンプルを要求する贅沢な人もいるかもしれない。

そんな人にはこんなサンプルを提示してやろう。そう、湯婆婆だ。
私のhtmlの知識は25年前で止まっているので「<br>はそういう使い方するな!」と逆に叱られてしまうかもしれない。
あと今回は省略しているが<meta charset="utf-8">などはちゃんと書いたほうがいいだろう。

app.py
from flask import Flask, render_template, request, redirect
import random

app = Flask(__name__)

@app.route("/")
def input():
    return render_template("input.html")

@app.route("/answer", methods=["post"])
def answer():
    name = request.form["inputname"]
    try:
        new_name = random.choice(name)
        return render_template("answer_named.html",
                               name = name,
                               new_name = new_name)
    except Exception as e:
        return render_template("answer_noname.html",
                               error = e)

if __name__ == "__main__":
    app.run(debug=True)
templates/input.html
<html>
<head>
<link rel="stylesheet" type="text/css" href="static/style.css">
</head>
<body>
<img src = "static/yuba.png"><br>
契約書だよ。そこに名前を書きな。<br>
<br>
<form action="/answer" method="post">
<textarea name="inputname"></textarea><br>
<button type="submit">POST</button>
</form>
</body>
</html>
templates/answer_named.html
<html>
<head>
<link rel="stylesheet" type="text/css" href="static/style.css">
</head>
<body>
<img src = "static/yuba.png"><br>
フン。<dev class="before">{{name}}</dev>というのかい。贅沢な名だねぇ。<br>
今からお前の名前は<dev class="after">{{new_name}}</dev>だ。いいかい、<dev class="after">{{new_name}}</dev>だよ。<br>
分かったら返事をするんだ、<dev class="after">{{new_name}}</dev>!!<br>
<br>
<a href="/">TOPに戻る</a>
</body>
</html>
templates/answer_noname.html
<html>
<head>
<link rel="stylesheet" type="text/css" href="static/style.css">
</head>
<body>
<img src = "static/haku.png"><br>
ありがとう 千尋。僕の名前は<div class="haku"> {{error}}</div><br>
君が僕の中にnullを入れて落ちてきたときの事、覚えているよ。<br>
エラーを拾おうとしたんだね。<br>
<br>
<a href="/">TOPに戻る</a>
</body>
</html>
static/style.css cssや画像はstaticフォルダに置く
.before {
    color: #FF0000;
    font-size: 120%;
    font-style: italic;
}

.after {
    color: #0000FF;
    font-size: 150%;
}


.haku {
    color: #FF00FF;
    font-size: 120%;
    font-weight: bold;
}

こういうのを眺めていると自分でもサイゼリヤ1000円ガチャが作れそうな気になってくる。この「自分でもできそうな気になる」というのが大事だと思うんだ。「Flaskを一から学びましょう、最初は標準出力でreturn "Hello World!"です。リピートアフタミー」ではモチベーションが上がらないよ。

終わりに

これまでずっとOpenCVで日本語を描いたり画像を合成したりということをやってきたので、ここでも「Flaskの中でOpenCVを使えばむかし流行ったまさに外道ジェネレータ的なやつを作れるようになるぜ!」という内容の記事を書くつもりだったのだが、湯婆婆が流行っているのでそちらに乗ってしまった。
現在はherokuを勉強中。

参考

Javaで湯婆婆を実装してみる
Javaで湯婆婆の出したエラーを回避する
 Pythonのtry ~ exceptなんてはじめて使った。
Pythonで湯婆婆を実装してみる