【Python】Flaskで簡易ポケモン図鑑を作ってみる【Flask】

Python
スポンサーリンク

 

前回、ちょっとだけ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>

流れとしては

  1. HTML側からPOSTを送信する
  2. Python(Flask)がPOSTを受け取り、if文にてPOSTを受け取った時の処理ブロックに入る
  3. render_template関数にてpokemondex.htmlを返す。その時第2引数にpoststr = poststrを入れることで、HTML側のpoststrにPythonのpoststrの値を代入する。

って感じ。余計分かりにくくなったかもですが・・・

こうすることで、テキストボックスと検索ボタンを消さず、その下に「POSTしたよ」というメッセージを見出しタグ(h1)を付けて表示させることができます。

ここまでできたらあとはPython側でごちゃごちゃすれば良さそうですね。

 

(5) HTMLのテキストボックス内の文字をPython側で取得する

今まではPython側からHTMLへ値を渡していましたが、実際にやりたいことは

  1. テキストボックスにポケモン名を入れてPOST
  2. テキストボックス内の文字(ポケモン名)をPython側に渡し、ごちゃごちゃ処理する
  3. 処理した結果を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処理のフローとしては

  1. pkname にテキストボックスの文字列を代入する
  2. テキストボックスに入力されたポケモン名を引数に、csvからそのポケモンのデータを引っ張ってきてpkdata に格納する。
  3. 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とか、デザイン側の勉強もしないとですね。

まあ、まずは機能面を作りきってからだと思いますけど・・・

コメント

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