Python の Flask
〜 Web サービスなしで Web フレームワーク 〜
2023-12-22 作成 福島
TOP > tips > python-flask
[ TIPS | TOYS | OTAKU | LINK | MOVIE | CGI | AvTitle | ConfuTerm | HIST | AnSt | Asob ]

1. Flask (フラスコ) をインストール

Linux の場合。
$ su
# dnf install python3-pip -y
# exit

$ pip install flask flask_httpauth

$ pip show flask flask_httpauth
Name: Flask
Version: 3.0.0
Summary: A simple framework for building complex web applications.
Home-page:
Author:
Author-email:
License:
Location: /home/who/.local/lib/python3.9/site-packages
Requires: click, Werkzeug, itsdangerous, Jinja2, blinker, importlib-metadata
Required-by: Flask-HTTPAuth
---
Name: Flask-HTTPAuth
Version: 4.8.0
Summary: HTTP authentication for Flask routes
Home-page: https://github.com/miguelgrinberg/flask-httpauth
Author: Miguel Grinberg
Author-email: miguel.grinberg@gmail.com
License:
Location: /home/who/.local/lib/python3.9/site-packages
Requires: flask
Required-by:

$ which flask
~/.local/bin/flask

$ flask --version
Python 3.9.16
Flask 3.0.0
Werkzeug 3.0.1
· コマンド pip は Windows でも同様の手順。(プロンプトは  PS C:\Users\who>  となる)
· コマンド which は Windows には存在しない。
· コマンド flask は Windows 版にも存在し、
%USERPROFILE%\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_不定文字列\LocalCache\local-packages\Python311\Scripts\flask.exe
をフルパスで指定すれば使えるが、ふつーはそこまでやらない。


2. 実装

2-1. GET で待ち受け
参照: 公式 Web ページのサンプル

$ python << EOF
from flask import Flask, request
from markupsafe import escape

app = Flask(__name__)

@app.route('/', methods=['GET'])        # methods=['GET','POST'] のように指定可能。省略すると GET のみになる。
def hello():
    name = request.args.get('name', 'world')
    return f'Hello, {escape(name)}.\n'

app.run(host='127.0.0.1', port=8080)    # port は指定なしだと 5000 で待ち受ける。
EOF



ここから下はアクセスログが表示される。Ctrl + C で終了。

* Serving Flask app '<stdin>' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. 警告: これは開発サーバです。本番環境で使用してはいけません。代わりに WSGI サーバを使用してください。*1 * Running on http://127.0.0.1:8080 Press CTRL+C to quit 127.0.0.1 - - [22/Dec/2023 15:26:07] "GET / HTTP/1.1" 200 - --- 下記 A の証跡 127.0.0.1 - - [22/Dec/2023 15:26:19] "GET /?name=Flask HTTP/1.1" 200 - --- 下記 B の証跡
*1 Flask をフロントエンドに使用せず、リバースプロキシ (waitress, gevent, nginx, Apache 等) の裏で使えと警告されている。
   (Flask はバージョン 1.0 からマルチスレッドがデフォルトだけど、内蔵の Werkzeug がサービスじゃないからか?)


別ウィンドウで動作テスト (GET)
$ curl localhost:8080                # --- A
Hello, world.

$ curl localhost:8080/?name=Flask    # --- B  
Hello, Flask.



PoorShell だとこんな感じ。
 >_ Windows PowerShell 
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

新しいクロスプラットフォームの PowerShell をお試しください https://aka.ms/pscore6

# Python で読み込むためリダイレクトの文字コードを UTF8 にする。*2
PS C:\Users\who> $OutputEncoding = [System.Text.Encoding]::GetEncoding('utf-8')

PS C:\Users\who> @"
from flask import Flask, request
from markupsafe import escape

app = Flask(__name__)

@app.route('/', methods=['GET'])
def hello():
    name = request.args.get('name', 'world')
    return f'Hello, {escape(name)}.\n'

app.run(host='127.0.0.1', port=8080)
"@ | python


* Serving Flask app '<stdin>' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:8080 Press CTRL+C to quit 127.0.0.1 - - [22/Dec/2023 15:30:19] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [22/Dec/2023 15:30:48] "GET /?name=Flask HTTP/1.1" 200 -
*2なぜか PowerShell はリダイレクトとファイル出力でエンコードの指定方法が異なる。

別ウィンドウで動作テスト (GET)
 >_ Windows PowerShell 
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

新しいクロスプラットフォームの PowerShell をお試しください https://aka.ms/pscore6

PS C:\Users\who> iwr http://localhost:8080 | select Content | ft -Wrap 

Content
-------
Hello, world.

PS C:\Users\who> iwr http://localhost:8080/?name=Flask | select Content | ft -Wrap 

Content
-------
Hello, Flask.

PS C:\Users\who>
コマンド長すぎ、センスダサすぎ。Microsoft は、この REPL が使いやすいと本気で思っているのだろうか。
登録済みの短縮名
· iwr : Invoke-WebRequest
· select : Select-Object
· ft : Format-Table


2-2. BASIC 認証で待ち受け

$ python << EOF
from flask import Flask, request
from markupsafe import escape
from flask_httpauth import HTTPBasicAuth

members = {
    'user1':'pass',
    'user2':'word',
}

app = Flask(__name__)
auth = HTTPBasicAuth()

@auth.get_password
def member_auth(name):
    return members.get(name)    # 平文のパスワードを返す。該当がなければ None を返す。

@app.route('/')
@auth.login_required
def hello():
    name = auth.username()
    return f'Hello, {escape(name)}.\n'

app.run(host='127.0.0.1', port=8080)
EOF


* Serving Flask app '<stdin>' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:8080 Press CTRL+C to quit 127.0.0.1 - - [22/Dec/2023 15:31:07] "GET / HTTP/1.1" 401 - 127.0.0.1 - - [22/Dec/2023 15:31:17] "GET / HTTP/1.1" 401 - 127.0.0.1 - - [22/Dec/2023 15:31:23] "GET / HTTP/1.1" 200 -

別ウィンドウで動作テスト (BASIC 認証)
$ curl localhost:8080
Unauthorized Access     --- 不許可。    

$ curl user1:word@localhost:8080
Unauthorized Access     --- 不許可。    

$ curl user1:pass@localhost:8080
Hello, user1.           --- 許可された。


2-3. POST で待ち受け

$ python << EOF
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['POST'])   # methods= はタプルにできない。
def post():
    values = {}
    names = request.form.keys()
    for name in names:
        values[name] = request.form[name]
    return values

app.run(host='127.0.0.1', port=8080)
EOF


* Serving Flask app '<stdin>' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:8080 Press CTRL+C to quit 127.0.0.1 - - [22/Dec/2023 15:42:57] "POST / HTTP/1.1" 200 - 127.0.0.1 - - [22/Dec/2023 15:43:10] "GET /?data_a=data1 HTTP/1.1" 405 -

別ウィンドウで動作テスト (POST)
$ echo 'data_a=data1&data_b=data2' | curl localhost:8080 -X POST -d @-
{"data_a":"data1","data_b":"data2"}

$ curl localhost:8080/?data_a=data1
<!doctype html>
<html lang=en>
<title>405 Method Not Allowed</title>   --- GET は許可してないので弾かれた。
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>
この方法は要求された URL で許可されていません。



PoorShell だとこんな感じ。
 >_ Windows PowerShell 
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

新しいクロスプラットフォームの PowerShell をお試しください https://aka.ms/pscore6

# Python で読み込むためリダイレクトの文字コードを UTF8 にする。
PS C:\Users\who> $OutputEncoding = [System.Text.Encoding]::GetEncoding('utf-8')

PS C:\Users\who> @"
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['POST'])
def post():
    values = {}
    names = request.form.keys()
    for name in names:
        values[name] = request.form[name]
    return values

app.run(host='127.0.0.1', port=8080)
"@ | python


* Serving Flask app '<stdin>' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:8080 Press CTRL+C to quit 127.0.0.1 - - [22/Dec/2023 16:00:36] "POST / HTTP/1.1" 200 -

別ウィンドウで動作テスト (POST)
 >_ Windows PowerShell 
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

新しいクロスプラットフォームの PowerShell をお試しください https://aka.ms/pscore6

PS C:\Users\who> echo "data_a=data1&data_b=data2" | iwr -Method POST http://localhost:8080 | select Content | ft -Wrap 

Content
-------
{"data_a":"data1","data_b":"data2"}

PS C:\Users\who>
コマンド長すぎ、センス··· (省略)。


2-4. 動的 URL で待ち受け

$ python << EOF
from flask import Flask
from markupsafe import escape

app = Flask(__name__)

@app.route('/function/<name>')            # --- C
def function(name):
    return f'Function {escape(name)}\n'

@app.route('/function/<name>/')           # --- D
def directory(name):
    return f'Directory {escape(name)}\n'

@app.route('/function/<name>/<func>')     # --- E
def dir_and_func(name,func):
    return f'Directory,Function {escape(name)},{escape(func)}\n'

app.run(host='127.0.0.1', port=8080)
EOF


* Serving Flask app '<stdin>' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:8080 Press CTRL+C to quit 127.0.0.1 - - [22/Dec/2023 16:06:36] "GET /function/aaa HTTP/1.1" 200 - 127.0.0.1 - - [22/Dec/2023 16:06:41] "GET /function/bbb HTTP/1.1" 200 - 127.0.0.1 - - [22/Dec/2023 16:06:47] "GET /function/ccc/ HTTP/1.1" 200 - 127.0.0.1 - - [22/Dec/2023 16:06:55] "GET /function/ccc/ddd HTTP/1.1" 200 - 127.0.0.1 - - [22/Dec/2023 16:07:03] "GET /function/ccc/ddd/ HTTP/1.1" 404 -

別ウィンドウで動作テスト (動的 URL)
$ curl localhost:8080/function/aaa
Function aaa                    --- 定義に適合した。(上記 C)

$ curl localhost:8080/function/bbb
Function bbb                    --- 定義に適合した。(上記 C)

$ curl localhost:8080/function/ccc/
Directory ccc                   --- 定義に適合した。(上記 D)

$ curl localhost:8080/function/ccc/ddd
Directory,Function ccc,ddd      --- 定義に適合した。(上記 E)

$ curl localhost:8080/function/ccc/ddd/
<!doctype html>
<html lang=en>
<title>404 Not Found</title>    --- 適合する定義が無かった。
<h1>Not Found</h1>
<p>The requested URL was not found on the server.
 If you entered the URL manually please check your spelling and try again.</p>
要求された URL がサーバ上に見つかりません。
 URL を手動で入力した場合は、綴りを確認して再試行してください。


3. おまけ

Flask を WSGI に対応させるには、mod_wsgi が必要になる。

WSGI の導入は、こちら を参照のこと。
(Django 用の記述なので、適宜読み替えることが必要)