10
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

flaskチートシート

10
Last updated at Posted at 2023-08-15

flaskもよく忘れるのでチートシートを作ってみました

一番基本のhttp

webアプリのサーバーがやっていることを超ざっくりいうとこんな感じです
image.png

flaskなどたいていのフレームワークは①②④をやってくれるのでプログラマが書くのはおもに③になります

リクエストとレスポンスは以下の通り
image.png

基本のコード

app.py
from flask import Flask				#Flaskをインポート

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

#ルーティングはデコレータがやってくれる
@app.route('/aaa', methods=['GET'])	#/aaaにgetメソッドでアクセスされたとき以下実行
def aaa():							#中身の関数
    return "<h1>hello</h1>"			#helloを太字で出力
	
if __name__ == "__main__":			#いつものやつw
    app.run(debug=True)				#デバッグオンで動かすと、コード変更時に楽なので

起動方法

サーバー起動  python app.py
ブラウザからは http://127.0.0.1:5000/aaa でアクセス

テンプレートを使う(jinja2)

htmlファイルは必ずtemplatesフォルダに格納すること
app.py
from flask import Flask, render_template	#新たなメソッドの導入

app = Flask(__name__)

@app.route('/aaa', methods=['GET'])
def aaa():
    return render_template("bbb.html")		#render_templateでbbb.htmlを呼び出す

if __name__ == "__main__":
    app.run(debug=True)
bbb.html
<html><head><meta charset="utf-8"></title></style></head> 
<body>
  <h3>world</h3>
</body></html>

テンプレートにパラメータを渡す

app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/aaa', methods=['GET'])
def aaa():
    return render_template("ccc.html",x=" wide",y=" web ")#ここで引数を渡している

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

うけとった引数を表示するには {{引数}} のように書く

ccc.html
<html><head><meta charset="utf-8"></title></style></head> 
<body>
  <h3>world{{x}}{{y}}</h3>
</body></html>

htmlからformでデータを送信(GET)

app.py
from flask import Flask, request, render_template
app = Flask(__name__)

@app.route('/', methods=['GET'])#フォームの送信
def index():
    return render_template('form.html')

@app.route('/ggg', methods=['GET'])#結果の処理
def index2():
    name = request.args.get('name')
    return render_template('form2.html', name=name)

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

form.html
<!DOCTYPE html>
<html>
<head>
    <title>Flask Form GET</title>
</head>
<body>
    <form action="/ggg" method="get">
        <input type="text" name="name">
        <input type="submit" value="Submit">
    </form>
</body>
</html>

結果を表示するためのhtml

form2.html
</head>
<body>
  <h2>{{name}}</h2>
</body>
</html>

htmlからformでデータを送信(POST)

app.py
from flask import Flask, request, render_template
app = Flask(__name__)

@app.route('/', methods=['GET'])#フォームの送信
def index():
    return render_template('formP.html')

#結果の処理部分
@app.route('/ggg', methods=['POST']) #POSTになっている点に注目
def index2():
    name = request.form.get('name')
    return render_template('form2.html', name=name)

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

フォーム(method="post"になっている)

formP.html
<!DOCTYPE html>
<html>
<head>
    <title>Flask Form GET</title>
</head>
<body>
    <form action="/ggg" method="post">
        <input type="text" name="name">
        <input type="submit" value="Submit">
    </form>
</body>
</html>

結果表示のためのhtml

form2.html
</head>
<body>
  <h2>{{name}}</h2>
</body>
</html>

テンプレート(jinja)に辞書を渡してキーとバリューを表示

前提 dicに辞書が入っている、pythonからは render_template(aaa.html result=dic)とする

aaa.html
    <ul>
        {% for key, value in results.items() %}
            <li>{{ key }}: {{ value }}</li>
        {% endfor %}
    </ul>

リダイレクト

app.pyの一部
from flask import Flask, redirect, url_for

リダイレクトの実装
以下の例は、/old にアクセスすると /new にリダイレクトされます

app.pyの一部
@app.route('/old')
def old_endpoint():
    return redirect(url_for('new_endpoint'))

@app.route('/new')
def new_endpoint():
    return "This is the new endpoint!"

リダイレクトは意外とわかりにくいので細かく解説します。

これのフローイメージは以下のとおりです

リダイレクト.png

①リクエスト(/old): クライアントが /old エンドポイントにアクセスを試みます。
②リダイレクト命令: サーバーはクライアントに対して、新しいエンドポイント /new にリダイレクトするよう命じます。これは通常、HTTPステータスコード302(一時的リダイレクト)または301(永続的リダイレクト)で行われます。
③リクエスト(/new): クライアントはサーバーからのリダイレクト指示に従い、自動的に /new エンドポイントに新たなリクエストを送信します。
④レスポンス文字列: /new エンドポイントからの応答として「This is the new endpoint!」という文字列がクライアントに送られます。

サーバー側のコードを再掲します。図と対比させてみてください。

app.pyの一部
@app.route('/old')               #①でココに飛んでくる
def old_endpoint():
    return redirect(url_for('new_endpoint')) #②のリダイレクト命令

@app.route('/new')               #③でここに飛んでくる
def new_endpoint():
    return "This is the new endpoint!"    #④のレスポンス文字列送信

そもそもリダイレクトとは?

たとえばサイトを引っ越したり、ページ名を変更したり(/about→/company)、ログインしていないのでログインページに誘導したり、モバイルユーザーをモバイル用のページへ誘導といった目的で使います、もしリダイレクトがなければ、古いURLにアクセスしたユーザーがエラー画面や空白ページを見てしまうことになります。
このように ユーザーを正しい場所に誘導するために存在するのがリダイレクトです。

その方法としてHTTPステータスコードの 301や302が使われます。

ステータスコード

ステータスコードは3桁の数字で、サーバーからの返事(成功、失敗、転送など)です。
最初の1桁でおおまかな「カテゴリ」が決まります。

1xx リクエスト継続中(ほぼ使わない)
2xx 処理に成功
3xx リダイレクト
4xx エラー
5xx サーバーエラー

200番代とか400番代は見たことがあるのではないでしょうか
300番代がリダイレクトに使われるコードです。

パスワードの暗号化

Flaskでパスワードを暗号化するために、bcryptというライブラリを使用します

pip install Flask-Bcrypt
app.pyの一部
from flask import Flask
from flask_bcrypt import Bcrypt

app = Flask(__name__)
bcrypt = Bcrypt(app)

パスワードの暗号化

ユーザーから受け取ったパスワード(pw)を暗号化します。

app.pyの一部
hashed_pw = bcrypt.generate_password_hash(pw).decode('utf-8')

パスワードのチェック

ユーザーがログイン時に入力したパスワードと、データベースに保存されているハッシュ化されたパスワードを比較

app.pyの一部
check = bcrypt.check_password_hash(hashed_pw, pw)
if check:
    print("Password is correct!")
else:
    print("Password is incorrect!")

セッション クライアント側にデータを保持する場合

セッションデータをクライアント側に持つのは、あまり良くないとされていますが、デフォルトの場合はこんな使い方になります

app.pyの一部
from flask import Flask, session

app = Flask(__name__)
app.secret_key = 'secret_key'# セッションの暗号化に使用される秘密鍵

# セッションから情報を取得する
var = session.get('result')  
#または
var = session['result']

キーがセッションに存在するかどうかが不明確な場合、KeyErrorを防ぐために session.get('result') のようなメソッドを使用することが推奨されます。しかし、キーの存在が保証されている場合、直接 session['result'] としてアクセスすることができます。

セッション サーバー側にデータを保持する場合

flaskはセッションデータをデフォルトではクライアント側に保持するのですが、安全性を高めたいときはサーバー側に持つのが良いとされています。(phpやdjangoではデフォルトがサーバー側)。というわけでサーバー側に保持する場合のやり方です。

app.pyの一部
from flask import Flask, session
from flask_session import Session

app.config['SECRET_KEY'] = 'your_secret_key_here'#秘密鍵
app.config['SESSION_TYPE'] = 'filesystem'#ファイルに保存
Session(app)

このあとは普通に

app.pyの一部
var = session.get('result')   #キーがない可能性がある場合
session["result"] = var       #キーが存在する場合

↑書き込みの場合

app.pyの一部
var = session["result"]

↑読み込みの場合(キーの存在を気にせず直接書き込めます)

flash()関数

シンプルなようで意外とわかりにくいのがflash()関数。chatGPTに聞くと
以下のように返ってきます
ーーーーーーーーーー
Flaskのflash()関数は、ユーザーへの一時的なメッセージを提供するために使用されます。これは、例えばフォームのバリデーションエラーや操作の成功・失敗の通知など、一時的なフィードバックが必要な場面で役立ちます。flash()関数で生成されたメッセージは、リクエスト間で一時的に保存され、次のリクエストで表示された後に消えます。
ーーーーーーーーーー

なるほどわからん! 
私はセッション付きのrender_template()関数と理解しました。以下サンプルとリクエストレスポンスのフローイメージです

app.py
from flask import Flask, flash, redirect, url_for, render_template
app = Flask(__name__)
app.secret_key = '!!#$%'  # セッションデータを暗号化するためのキー

@app.route('/sample')
def sample():
    flash('This is a flash message!')
    #このメッセージは最終的にindex.htmlに渡されるが一時的にセッションに保存
    return redirect(url_for('index'))

@app.route('/')
def index():
    return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=True)
 index.html
<!DOCTYPE html>
<html>
<head>
    <title>Flash Example</title>
</head>
<body>
    {% for message in get_flashed_messages() %}#ここでセッションから取り出される
        <div>{{ message }}</div>
    {% endfor %}
</body>
</html>

上のコードでのやり取り (リクエストレスポンスのフローイメージ)

image.png

blueprint

webアプリの機能が増えてくると、とうぜんファイルを分割したくなります。このときappというインスタンス(一番さいしょn基本でつくったやつ)を各モジュールの中で使い回すのがやっかいになってきます。

そこで、appインスタンスに相当するインスタンスを各モジュールで作成しておいてapp.pyではこれらをimportし、登録しておくと機能を追加してもモジュール単位で独立しているので管理がしやすくなります。

image.png

ちなみにappインスタンスとは

app.pyの一部
from flask import Flask				#Flaskをインポート
app = Flask(__name__)				#インスタンス作成

でつくったインスタンスで、run()やroute()などのメソッドやプロパティをもっています
chatGPTに調べてもらったら以下のようにでてきました

メソッド
image.png

プロパティ
image.png

10
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?