flaskはpythonでウェブアプリケーションを作るためのライブラリである。ここでは、flaskを使ううえでの基本的な方法をまとめる。
#インストール
pip install flask
#導入
まず最初に、最も簡単な"Hello World"を返すAPIを作る。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def root():
return "Hello World!"
if __name__ == "__main__":
app.run()
- 関数
@app.route(url)
でデコレートすると、そのurlにアクセスすると、その関数が実行されるようになる。
python app.py
上で作成したapp.py
を実行すると、ウェブサーバーが起動する。ブラウザでhttp://localhost:5000/
にアクセスすると、画面にHello World!
が表示されるようになる。
#開発時の設定
from flask import Flask
app = Flask(__name__)
@app.route('/')
def root():
return "Hello World!"
if __name__ == "__main__":
app.run(debug=True,host='localhost',port=5000)
-
main
を上のように変える。 -
debug=True
を渡すと(デバッグモード)、サーバーが起動している時に、app.py
や後述するhtmlファイルなどを変更した時に、自動的にロードされる。debug
の初期値はFalse
。 -
host
・port
は自由に決めれる。port
の初期値は5000。
#外部からアクセスできるようにする。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def root():
return "Hello World!"
if __name__ == "__main__":
app.run(debug=False,host='0.0.0.0',port=5000)
-
main
を上のように変える。 -
host=localhost
の時にはローカルからしかアクセスできない。外部からアクセスできるようにするには、host="0.0.0.0"
。 - セキュリティの理由から
debug=False
にする。
#ブラウザも同時に起動する
import threading,webbrowser
from flask import Flask
app = Flask(__name__)
@app.route('/')
def root():
return "Hello World!"
if __name__ == "__main__":
threading.Timer(1.0, lambda: webbrowser.open('http://localhost:5000') ).start()
app.run(debug=False)
-
main
でブラウザーを開くコマンドを追加する。 -
app.py
を実行すると同時にブラウザーが立ち上がり、ページが表示される。 -
app.run()
にdebug=True
を渡すと、コードを変更するたびにmain
が再実行されるため、その度にブラウザーが追加で開いてしまう。それを防ぐためdebug=False
を渡している.
デバッグモード(debug=True
)でブラウザーを自動で開くようにしたい時には、main
は
if __name__ == "__main__":
app.run(debug=True)
にして、
#!/bin/sh
( sleep 2; open http://localhost:5000/ ) &
python app.py
のようなシェルスクリプトを実行するような方法がある。
#htmlファイルを返す
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def main():
return render_template('index.html')
if __name__ == "__main__":
app.run()
<html>
<body>
Hello World!
</body>
</html>
- htmlファイルを返す時には
render_template(file)
を用いる。 - htmlファイル(ここでは
index.html
)はapp.py
と同じ場所にtemplates
というディレクトリを作り、その中に配置する。 -
http://localhost:5000/
にブラウザからアクセスするとindex.html
がレンダリングされ、この場合は"Hellow World!"が表示される。
#CSS・JavaScriptファイル
- CSSファイルやJavaScriptファイルはディレクトリ
./static
に配置する。画像もここに配置する。 - htmlファイルからは、それぞれ
<head>
<script src="/static/script.js"></script>
<link rel="stylesheet" href="/static/style.css">
</head>
のように呼び出す。
#GETリクエスト
- ここでは
/get
のアドレスにGETリクエストを受けて、{"message":"Hello World!"}
というjsonオブジェクトを返すapiを考える。
from flask import Flask,request,jsonify,render_template
app = Flask(__name__)
@app.route('/')
def index_html():
return render_template('index.html')
@app.route('/get',methods=['GET'])
def get():
return jsonify({'message':'Hello world!'})
if __name__ == '__main__':
app.run()
- デコレータ
@app.route(url,methods)
でリクエストを受け入れるurl
とmethods
を指定。 -
jsonify()
はオブジェクトを文字列になおし、適切なレスポンスを生成する関数である。
<html>
<body>
<button onclick='get();'>get</button>
<script>
function get(){
fetch('/get').then(
response => response.json()
).then(
json => { document.body.innerHTML += JSON.stringify(json); }
).catch(
e => console.error(e)
);
}
</script>
</body>
</html>
- ボタンを押すと、返ってくるJSONを文字列として表示される。
fetchが成功したい時に何か処理を行いたい時には、次のようにすれば良い。
fetch('/get').then(
response => (
if (response.ok){
//成功時に行ないたい処理
} else {
throw new Error()
}
).catch(
e => console.error(e)
);
#POSTリクエスト
- ここでは
/post
のアドレスにPOSTリクエストを受けて、同じJSONをそのまま返すapiを考える。
from flask import Flask,request,jsonify,render_template
app = Flask(__name__)
@app.route('/')
def index_html():
return render_template('index.html')
@app.route('/post',methods=['POST'])
def post(): #送られてきたjsonをそのまま返す。
req = request.json
return jsonify(req)
if __name__ == '__main__':
app.run()
- POSTリクエストで送られてきたJSONは
request.json
で得られる。
<html>
<body>
<button onclick='post();'>post</button>
<script>
function post(){
fetch('/post', {
method: "POST",
headers: { "Content-Type": "application/json"},
body: JSON.stringify({"message": "Hello World!!!"})
}).then(
response => response.json()
).then(
json => { document.body.innerHTML += JSON.stringify(json); }
).catch(
e => console.error(e)
);
}
</script>
</body>
</html>
- ここでは、ボタンを押すと
{'message':'Hello World!!!'}
のJSONをデータとして持つPOSTリクエストを送る。同じJSONが返ってくるのでそれを表示する。
#画像データを返すAPI
サーバーはデータを受信し、matplotlibでグラフを作成し、その画像データを返すようなAPIを考える。ここでは画像データをdataURLに変換してデータを返す。dataURLは画像データをurlとして表現したものである。
from flask import Flask,render_template,jsonify,request
import matplotlib
matplotlib.use('agg')
from matplotlib import pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg
import io,base64
app = Flask(__name__)
@app.route('/')
def main():
return render_template('index.html')
@app.route('/image',methods=['POST'])
def image():
data = request.json
x = data['x']
y = data['y']
#図を作成
plt.figure(figsize=(3,3),dpi=100)
plt.plot(x,y,'k*-',markersize=10)
#図をdataURLに変更
canvas = FigureCanvasAgg(plt.gcf())
png_output = io.BytesIO()
canvas.print_png(png_output)
img_data = base64.b64encode(png_output.getvalue()).decode('utf-8')
dataurl = 'data:image/png;base64,'+img_data
return jsonify({'img_data':dataurl})
if __name__ == "__main__":
app.run()
- まず、サーバー上での図の描画になるので、下のコマンドを
matplotlib
関連のライブラリのimportの一番最初に行うことに注意する。
import matplotlib
matplotlib.use('agg')
-
image()
ではmatplotlibでデータからグラフを作成し、それをdataURLに変換し、それを返している。
<html>
<body>
<button onclick="image();">img</button>
<div id='img'></div>
<script>
function image(){
fetch('/image', {
method: "POST",
headers: { "Content-Type": "application/json"},
body: JSON.stringify({"x":[0,1,2,3,4,5], "y":[5,2,4,0,3,8]})
}).then(
response => response.json()
).then(
json => { document.getElementById('img').innerHTML = `<img src="${json['img_data']}">`; }
).catch(
e => console.error(e)
);
}
</script>
</body>
</html>
- imgボタンをクリックすると、データ
x=[0,1,2,3,4,5]
、y=[5,2,4,0,3,8]
をサーバーに送る。 - レスポンスが返ってきたら、dataURLをimgタグのsrcに入れれば画像が表示される。
#クロスオリジンリクエスト(COR):別のドメインからのアクセス
デフォルトでは別のドメインからのアクセスは制限されている。これを許可するためにはflask-cors
のパッケージを使う。
pip install flask-cors
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route('/')
def root():
return "Hello World!"
if __name__ == "__main__":
app.run()
- 単に
CORS
をapp
に適用するだけでOK。
#ユーザー認証(ダイジェスト認証)
認証のためにflask-httpauth
のパッケージを用いる。
pip install flask-httpauth
from flask import Flask
from flask_httpauth import HTTPDigestAuth
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret key here'
auth = HTTPDigestAuth()
users = {
'Michael': 'pw_m',
'Smith': 'pw_s'
}
@auth.get_password
def get_pw(username):
if username in users:
return users.get(username)
return None
@app.route('/')
@auth.login_required
def root():
return "Hello World!"
if __name__ == "__main__":
app.run()
- ユーザー名を与えられた時に、そのユーザーが存在するならば、そのユーザーのパスワードを返し、ユーザーが存在しないならば、
None
を返す関数を作り(get_pw
)、それを@auth.get_password
でデコレートする。 - ここではユーザは'Michael'と'Smith'二人存在し、パスワードはそれぞれ'pw_m'、'pw_s'であるとする。
- 認証が必要な関数を
@auth.login_required
でデコレートする。 - アクセスすると認証画面が最初に表れ、正しいユーザー名・パスワードを入力すると、"Hello World"が表示される。