前回、ちょっとだけFlaskのお勉強会をブログにまとめました。
今回はもっと応用して、Flaskで簡易的なポケモン図鑑を作ってみようと思います。
要件
- テキストボックスとボタンを用意する
- テキストボックスにポケモン名を入力してボタンを押下すると、ポケモンの簡易データを表示する
たったこれだけ。
これだけなのにめっちゃ時間かかりました・・・。
フォルダ階層
フォルダの構造はこんな感じ。
黒塗りしているところは今回全く関係ないプログラムとか。
./python/flask 直下にpythonプログラムを配置しています。
./python/flask/csv 配下にはポケモンのデータ等をまとめているcsvファイル。
./python/flask/templates 配下にはHTMLのテンプレートファイルが存在します。
それぞれの役割はまあおいおい説明するとして・・
前回はpythonファイルのみでブラウザ表示させていましたが、今回はHTMLテンプレートを使ってよりHTMLっぽく作成したいと思います。
というか、前回は単純にプレーンテキストを表示させただけだからね・・・
HTMLでも何でもなかったからね・・・
まあ、今回もHTMLあんまり関係ないんだけど・・・
ポケモン図鑑作成への道
今回はいきなり答えを持ってくる形式ではなく、試行錯誤した証を残していく形式にしていきます。
というか、結局のところただの自学自習のため、軌跡が大事なんですよね。
今回作るツールに実用性があるとは自分でも思っていませんし・・・
(1) FlaskでHTMLテンプレートを読みだす
まずは要件1の「テキストボックスとボタンを用意する」を実現します。
とはいえ、前回のようにただ単純にプレーンテキストをブラウザに表示させるだけでは全く持って実現不可能です。
ので、今回はちゃんとHTMLタグを使ってブラウザへアウトプットしようと思います。
んで、どうやってFlaskでHTMLタグを表示させようかというと、一番当たり障りのない方法である「HTMLテンプレート」を利用する方法にしました。
簡単に言うと、Python(Flask)から、事前に用意したHTMLファイルを読みだしてそれを表示させる感じの方法ですね。
HTMLテンプレートを使用するには階層の部分で説明したように、起動するpythonファイルが存在する階層に「templates」フォルダを作成して、そこにHTMLファイルを配置する必要があります。
というわけで、まずはPython側。
# pokedex.py
# coding:utf-8
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def index():
return render_template('pokemondex.html')
if __name__ == "__main__":
app.debug = True
app.run(host='0.0.0.0')
render_templateにて、templatesフォルダに格納しているHTMLファイルを読みだすことができます。
今回は、./templates/pokemondex.html を読みだしています。
HTML側はこちら。
<!DOCTYPE html>
<html lang="ja">
<head>
</head>
<body>
<form action="/" method="post">
<input type="text" name="pkname" value="ポケモン名">
<input type="submit" value="送信">
</form>
</body>
</html>
テキストボックスとsubmitボタンを配置しているだけの簡単なHTMLですね。
ボタンを押下するとPOSTを送信するようになっています。
Flaskを起動してブラウザで表示するとこんな感じ。
※Flaskの起動の仕方は前回記事を参照
ボタンを押すと・・・
メソッドが許可されていない的なエラーが出力されます。
POSTを送ったけど、Flask側が対応していないのでエラーを返した感じです。
(2) POSTを許可する
POSTが許可されていないので、FlaskにPOSTを許可するように記述します。
# coding:utf-8
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST']) # GET,POSTメソッドを追加
def index():
return render_template('pokemondex.html')
if __name__ == "__main__":
app.debug = True
app.run(host='0.0.0.0')
これでボタンを押すと・・・
エラーは出なくなりましたが何も起きません。
POSTを受けたときの処理を何も書いていないのでそりゃそうだ。
(3) POSTを受け取った際の処理を追加する
POSTを許可したはいいが、POSTを受け取っても今のままでは全く仕事をしてくれないので、POSTを受け取った時の処理を追加します。
今回はテストとして、POSTを送信したら「POST」という文字を表示させたいと思います。
というわけでpythonをいじる。
# coding:utf-8
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET': # GETされたとき
return render_template('pokemondex.html')
elif request.method == 'POST': # POSTされたとき
return 'POST'
if __name__ == "__main__":
app.debug = True
app.run(host='0.0.0.0')
request.methodでリクエストメソッドを判定することができます。
ので、そいつをif文で処理させてあげます。
この状態でボタンを押下すると、POST送信されて以下出力されるようになります。
しかしこれだけでは何がなんやらわかりませんね・・・。
しかも、ページ自体が変わってしまっているように見えてしまいます。
連続で検索できるように、テキストボックスと検索ボタンは残したまま、その下にテキスト表示させたいのですが、この実装だとそれができません。
(4) HTMLタグで表示させる
流石にプレーンテキストで表示させるのは安っぽすぎるので、ちゃんとタグで返すようにします。
方法としては、先ほど作成したHTMLテンプレートに変数を用意し、jinja2にてPython→HTMLへ値を渡してあげます。
多分これはソース見てもらったほうが理解しやすいと思われます。
# coding:utf-8
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
return render_template('pokemondex.html')
elif request.method == 'POST':
poststr = 'POSTしたよ'
return render_template('pokemondex.html', poststr = poststr) #jinja2を使ってHTMLに文字列を送る
if __name__ == "__main__":
app.debug = True
app.run(host='0.0.0.0')
<!DOCTYPE html>
<html lang="ja">
<head>
</head>
<body>
<form action="/" method="post">
<input type="text" name="pkname" value="ポケモン名">
<input type="submit" value="送信">
</form>
<h1>{{ poststr }}</h1> #Python側から値を受け取る
</body>
</html>
流れとしては
- HTML側からPOSTを送信する
- Python(Flask)がPOSTを受け取り、if文にてPOSTを受け取った時の処理ブロックに入る
- render_template関数にてpokemondex.htmlを返す。その時第2引数にpoststr = poststrを入れることで、HTML側のpoststrにPythonのpoststrの値を代入する。
って感じ。余計分かりにくくなったかもですが・・・
こうすることで、テキストボックスと検索ボタンを消さず、その下に「POSTしたよ」というメッセージを見出しタグ(h1)を付けて表示させることができます。
ここまでできたらあとはPython側でごちゃごちゃすれば良さそうですね。
(5) HTMLのテキストボックス内の文字をPython側で取得する
今まではPython側からHTMLへ値を渡していましたが、実際にやりたいことは
- テキストボックスにポケモン名を入れてPOST
- テキストボックス内の文字(ポケモン名)をPython側に渡し、ごちゃごちゃ処理する
- 処理した結果をHTMLとして表示する(HTMLテンプレートに値を渡す)
って感じなので、テキストボックスに入力した文字列をPython側になんとか渡さないといけません。
その時に使用するのがrequest.form[]関数。(関数なのか?)
# coding:utf-8
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
return render_template('pokemondex.html')
elif request.method == 'POST':
poststr = request.form["pkname"] #name="pkname"のフォームのValueを取得する
return render_template('pokemondex.html', poststr = poststr)
if __name__ == "__main__":
app.debug = True
app.run(host='0.0.0.0')
request.form[“pkname”]によって、テキストボックスの文字列をPython側の変数に代入することができます。
実行してみるとこんな感じ。
先ほどは「POSTしたよ」というメッセージしか表示できませんでしたが、今回はテキストボックスに入力された文字列を見出し文で表示することができました。
これを使えばHTMLとPythonで値のやり取りができるわけですね。
(6) ポケモン名を入力してPOSTしたらそのポケモンの英語名を出すようにする
ここからよりPythonらしい処理をさせていきます。
事前に用意しておいたポケモンのデータを記載しているcsvを読み込んで、ポケモン名から色々処理をさせてみます。
一番簡単なところで、まずはポケモン名を入れると英語名に変換してくれるようなシステムを作成します。
# coding:utf-8
from flask import Flask, render_template, request
import pokeObjectClass # ポケモンの情報を管理するクラス(構造体みたいなもの)
import getPokeData # csvからポケモンの情報を返す自作ライブラリ
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
return render_template('pokemondex.html')
elif request.method == 'POST':
pkname = request.form["pkname"] # 入力されたポケモン名を変数に代入
pkdata = getPokeData.getPokemonDetail(pkname) # 入力されたポケモン名からcsv検索してそのポケモンのデータを取得
return render_template('pokemondex.html', poststr = pkdata.pokeNameENG) # 入力されたポケモンの英語名をHTMLに渡す
if __name__ == "__main__":
app.debug = True
app.run(host='0.0.0.0')
自作ライブラリを実装したのでちょっとわかりにくくなってしまっていますが、
pokeObjectClass は構造体のようなもので、ただの変数をまとめて管理するだけのクラスです。
getPokeData はcsvからポケモンのデータを引っこ抜いて、pokeObjectClass型にして返すライブラリ。
やっていることは単純なので説明は省きます。
このPython処理のフローとしては
- pkname にテキストボックスの文字列を代入する
- テキストボックスに入力されたポケモン名を引数に、csvからそのポケモンのデータを引っ張ってきてpkdata に格納する。
- pkdata のデータの1つであるポケモンの英語名(pokeNameENG)をHTMLテンプレート側に渡して表示する
って感じ。単純です。
実際に動作させると
どやああああ
ちゃんと変換できてますね。
さてここまで来たらあとは消化試合です。
(7) 簡易ポケモン図鑑の完成!
ポケモンのデータを引っこ抜いて格納できるところまで完成したので、あとは必要なデータを全てHTMLテンプレート側に渡して表示させるだけです。
というわけで早速PythonとHTMLのソース。
# coding:utf-8
from flask import Flask, render_template, request
import pokeObjectClass # ポケモンの情報を管理するクラス(構造体みたいなもの)
import getPokeData # csvからポケモンの情報を返す自作ライブラリ
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
return render_template('pokemondex.html')
elif request.method == 'POST':
pkname = request.form["pkname"] # 入力されたポケモン名を変数に代入
pkdata = getPokeData.getPokemonDetail(pkname) # 入力されたポケモン名からcsv検索してそのポケモンのデータを取得
pkname = pkdata.pokeNameJP
engname = pkdata.pokeNameENG
num = pkdata.pokeWldNum
gnum = pkdata.pokeGrlNum
type = ''
for t in pkdata.poketype:
type += (t + '/')
ability = ''
for a in pkdata.pokeAbility:
ability += (a + '/')
height = pkdata.pokeHeight
weight = pkdata.pokeWeight
return render_template('pokemondex.html', pkname = pkname \
, engname = engname \
, num = num \
, gnum = gnum \
, type = type[:-1] \
, ability = ability[:-1] \
, height = height \
, weight = weight) # 入力されたポケモンの英語名をHTMLに渡す
if __name__ == "__main__":
app.debug = True
app.run(host='0.0.0.0')
<!DOCTYPE html>
<html lang="ja">
<head>
</head>
<body>
<form action="/" method="post">
<input type="text" name="pkname" value="">
<input type="submit" value="送信">
</form>
<h1>{{ pkname }}</h1>
<p>ポケモン名: {{ pkname }}</p>
<p>英語名: {{ engname }}</p>
<p>全国図鑑番号: {{ num }}</p>
<p>ガラル図鑑番号: {{ gnum }}</p>
<p>タイプ: {{ type }}</p>
<p>特性: {{ ability }}</p>
<p>身長: {{ height }}</p>
<p>体重: {{ weight }}</p>
</body>
</html>
原理はさっきの英語名を表示させるものと全く同じです。
単純にrender_templateで渡す引数を多くして、HTMLテンプレート側に必要なものを全て渡しているだけです。
実行してみるとこんな感じになりました。
ポケモンの画像が無かったり、全部黒文字だったりと見栄えは乏しいですが、かなりそれっぽいシステムになりました。
あとはcssで装飾してあげたり、画像を挿入してあげたりするともっとそれっぽくなります。
時間があればやってみたいですが、まあやらんだろうな・・・
というわけで、知識ほぼ0から作るFlaskでのポケモン図鑑でした。
一応、890匹分のデータはcsvで整理済みなので、ほぼすべてのポケモンは網羅しております。
ただ、実用性があるかというと・・・まあポケモン徹底攻略様見ればいいしね。
今回の経験を通して、本題であるダメージ計算ツールや努力値計算ツールをWEBアプリ化していきたいですね。いつになるかわからんが
まとめ
- Flaskで簡単なポケモン図鑑ツールを作ってみた
- HTMLテンプレートを使ったWEBアプリケーションの仕組みを理解
- Flask楽しいかもしれん
あとはcssとか、デザイン側の勉強もしないとですね。
まあ、まずは機能面を作りきってからだと思いますけど・・・
コメント