[Python初心者向け]Flaskの使い方



[Python初心者向け]Flaskの使い方

Pythonの Webフレームワークを学習するときに必ずといっていいぐらい登場する Flask。

Bottle 以上、 Django 未満な "Flask" を体験してみませんか?

あなたの Python スキルをブートアップしてくれることでしょう。

Hello World からルートディレクトリの設定、ファイルのアップロードまでを公式ドキュメントに沿ってご紹介させて頂きます。

本稿は、 Python の基礎を習得済みの方を対象としています。予め、ご了承ください。

目次
  1. Python初心者向け_Flaskの使い方
  2. Flaskとは
  3. Flaskを扱う様子の動画
  4. Flaskをインストール
  5. FlaskでHelloWorld
  6. FlaskでURLのルート設定
  7. Flaskで変数を使ったURLのルート設定
  8. Flaskのurl_for()
  9. FlaskのGET・POST
  10. Flaskのテンプレートを使う
  11. Flaskでファイル・アップロード
  12. まとめ

Python初心者向け_Flaskの使い方

Flaskとは

image

https://flask.palletsprojects.com/en/1.1.x/

Flask は、 Python用の Webフレームワークで 2010年にオーストラリア出身の Armin Ronacherさんが 20歳の時に開発したフレームワーク。詳しい開発の経緯は不明ですが、 2018年の Python Developer Survey で最も人気のあるフレームワークに。 Flask と同じ Webフレームワークに Bottle と Django がありますが、 Bottle 以上 Django 未満の機能を持つ Flask は、 Python 初心者から上級者まで使い勝手のいいもの。

GitHub上のレポジトリを検索しても Bottle が 7,184リポジトリなのに対して Flask は 129,419* という 10倍以上の人気ぶり。

ただし注意点としては、 Flask でもデータベースと連携したアプリケーションを作成できますが、 Flask 自体はデータベースをネイティブでサポートしていません。 データベースの活用を考えるならワンランク上の "Django" の方が好ましいかな、と思います。

それでは自分のパソコンに Flask をインストールして、使っていきましょう。

Flaskを扱う様子の動画

本稿でご紹介するプログラムを実行する様子です。本テキストと合わせてご参照ください。

本稿で使用するコード: GitHub

Flaskをインストール

image

https://flask.palletsprojects.com/en/1.1.x/

Flask 公式ページで紹介されています 「Installation」 に従ってインストールを実行していきます。

上図のコード

python3 -m venv myenv
source myenv/bin/activate
pip install Flask
(Mac、 Linux の場合)

まずは仮想環境を作成し、仮想環境をアクティベート。それから pip install flask で Flask をインストール。 この pip install の時の flask は、 Flask でも flask でもどちらでもインストールできました。

Flask がインストールできたら、早速 Hello World で Flask を動かしてみましょう。

FlaskでHelloWorld

上図のコード

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World'

Flask の公式ドキュメントは、いろいろリンクがあってどこから進めていけば迷いますが、 Quickstart のレシピに従って進めると、大まかな Flask を体験できます。

Quickstart の最初に紹介されているコードをコピペ(上図参照)。 今回は hello.py というファイル名で保存。

そしてプログラム・ファイルが用意できたら、通常は python hello.py でプログラムを実行すると思いますが、公式ドキュメントによると Flask App に hello.py のパスを通してから Flask を実行してくださいとのこと。上図のようにマニュアル通りにパスを通して Flask を実行すると Hello World が出力されました。


【Windowsで Flask を実行する場合】

公式ドキュメントに従うと、 Windows の場合は Flask を実行する手順がちょっと面倒。コマンドラインでパスを通して、それから PowerShell で設定して、 Flask を実行という手順。公式ドキュメントのとおりに実行すると手間ですが、プログラムを少し変更すると python hello2.py で Flask プログラムを実行できます(下図参照)。

上図のコード

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

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

ネット上の Flask のサンプルコードなどを見ていると、どちらかというと、公式ドキュメントのやり方よりは hello2.py で実行した方法の方が多いように思います。いずれにしても Flask は実行されますので、扱いやすい方で始めていきましょう。


FlaskでURLのルート設定

上図のコード

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return 'Index Page'

@app.route('/hello')
def hello():
    return 'Hello, World'

Hello World が出力できたところで、 公式ドキュメントの Quickstart を進めていくと次は "Routing" に関する内容。先ほどの Hello World のプログラムを元に、公式ドキュメントのコードをコピペし、 routing.py というファイル名で保存。

プログラムを実行してみると、トップディレクトリに Index Page、 localhost:5000/hello に Hello World を出力できました。 Bottle に比べるとルート設定がシンプルであることが確認できます。

Flaskで変数を使ったURLのルート設定

上図のコード

from flask import Flask
app = Flask(__name__)

@app.route('/user/')
def show_user_profile(username):
    return 'User %s' % escape(username)

@app.route('/post/')
def show_post(post_id):
    return 'Post %d' % post_id

@app.route('/path/')
def show_subpath(subpath):
    return 'Subpath %s' % escape(subpath)

次は変数を使った Routing。このあたりから一気に難しくなります。

とりあえず公式ドキュメントに書かれているコードをコピペし、 routing2.py で保存。そして実行してみると、下図のようにエラーが...

プログラム的には 3つのディレクトリが設定されていますが、真ん中の post 以外はエラー。ターミナルに表示されているエラー文を確認すると NameError: name 'escape' is not defined 、つまり escape モジュールがインポートされていないということ。 import 部分に escape を加えると、見事 3つのディレクトリで文字を出力することができました(下図参照)。

上図のコード

from flask import Flask, escape
app = Flask(__name__)

@app.route('/user/')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % escape(username)

@app.route('/post/')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

@app.route('/path/')
def show_subpath(subpath):
    # show the subpath after /path/
    return 'Subpath %s' % escape(subpath)

3つの出力、 user も id も path もどれも URL と表示内容が同じ。これはユーザー管理や商品管理、 ページの id 管理などをしたい時に便利そう。プログラム内に書かれている %s%d は、 "書式指定" を使ったプログラム。上記画像では < など入力されていないのでわかりにくいですが、 URL のところに < を入れると自動的に &lt; に変換されます。つまりスクリプトなどで悪さされないように、エスケープしてくれるんですね。

Flaskのurl_for()

上図のコード

from flask import Flask, escape, url_for

app = Flask(__name__)

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

@app.route('/login')
def login():
    return 'login'

@app.route('/user/')
def profile(username):
    return '{}\'s profile'.format(escape(username))

with app.test_request_context():
    print(url_for('index'))
    print(url_for('login'))
    print(url_for('login', next='/'))
    print(url_for('profile', username='John Doe'))

次はもう少しややこしくなって url_for() を使った URL の取り扱い。まずはサンプルコードをコピペして、プログラムを実行してみましょう。

flask run を実行すると、ターミナル内に URL に関する記述が 4行表示されました。これは 18行目から 21行目の内容が表示されているのですが、 url_for(〇〇) を使うことで、 URL を指定できることを表しています。

例えば 18行目の url_for('index') は、 6行目の def index(): 部分の働きを行い、 21行目の url_for('profile', username='John Doe') は 14行目の def profile(username): の働きを実行。

このサンプルではチョット url_for() の動きがつかみにくいので、 下図のようにログアウトのプログラムを作成してみました。

上図のコード

from flask import Flask, escape, url_for, redirect

app = Flask(__name__)

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

@app.route('/login')
def login():
    return 'login'

@app.route('/logout')
def logout():
    return url_for("index")

@app.route('/user/')
def profile(username):
    return '{}\'s profile'.format(escape(username))

with app.test_request_context():
    print(url_for('index'))
    print(url_for('login'))
    print(url_for('login', next='/'))
    print(url_for('profile', username='John Doe'))

13行目から 16行目がログアウトに関するコードで、 URL localhost:5000/logout にアクセス(②部分)したら url_for("index") が働き、 ③部分の def index() のプログラムが実行。

このように url_for() は、ページ間の移動処理を手伝ってくれる機能で、注文後の完了画面や演算後の完了画面などによく使われます。チョット最初はイメージしにくい機能ですが、使えるようになると便利なので頑張ってマスターしましょう。

FlaskのGET・POST

上図のコード

from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        return do_the_login()
    else:
        return show_the_login_form()

さて Quickstart の公式ドキュメントを進めていくと、次は "GET" "POST" などの HTTPメソッド。 Flask は API を公開したりするときもよく使いますので、 "GET" "POST" も感覚をつかんでおきましょう。

とりあえずは上図のように公式ドキュメントのコードをコピペ。ただこのままでは import 文に Flask がないですし、 return 文のところの do_the_login() などの関数もありません。少し以下のようにプログラムを変更し、実行。

上図のコード

from flask import request, Flask
app = Flask(__name__)

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        return "do_the_login()"
    else:
        return "show_the_login_form()"

プログラムを実行し、 localhost:5000:login にアクセスすると、ターミナル上に GET と表示されて、ブラウザ上は "show_the_login_form()" という文字が。この文章は、 9行目の return文で、 POST ではなく GET だから処理された内容。つまり URL にアクセスすると GET でデータを取得していることが確認できますね。

GETではなく POST を試そうと思うと、何だかの情報入力が必要に。以下のように簡単な入力項目を設けてテストしてみました。

上図のコード

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

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        return '''
        <form action="#" method="post">
            <p>ユーザー名: <input type="text" name="nm" />
            <input type="submit" value="check"/>
            </p>
        </form>
        '''
    elif request.method == 'POST':
        user = request.form["nm"]
        return "<h2>ユーザー名: " + user + "</h2>"

プログラム実行後、 localhost:5000 にアクセスすると GET メソッドで入力画面が表示。そして名前を入力し、 checkボタンを押すと画面が切り替わり 「ユーザー名: oshima」 と表示。 ターミナル上では、 check ボタンを押した瞬間に POST メソッドが実行。

このように "GET" "POST" を使うと、 "入力欄" と "その入力に対する結果" を操作することができます。 Webフレームワーク Bottle に比べると、このあたりの処理コードは Flask の方がシンプルで、制御しやすいことが確認できます。

ただ入力欄を表現するためのコードが 8から12行目で書かれているのですが、できればもう少しスッキリした形で制御したいもの。 Flask には "Template" 機能もありますのでそちらを使って HTML コードをスッキリ管理してみたいと思います。

Flaskのテンプレートを使う

上図のコード

【web01.py】
from flask import render_template, Flask
app = Flask(__name__)

@app.route('/hello/')
@app.route('/hello/')
def hello(name=None):
    return render_template('hello.html', name=name)

【hello.html】
<h1>こんにちは、 Flask</h1>

テンプレートの使い方は公式ドキュメントの Quickstart にも書かれていて、とりあえず上図のようにコードをコピペ。コードの最終行を見ると "hello.html" というファイル名が指定されています。つまり Flask でテンプレートを使う場合は、専用の HTMLファイルや CSSファイルを用意する必要が。

また単に hello.html をセットすればいいというのではなく、 templates という決まった形のディレクトリ内に hello.html を保存する必要があります。このテンプレートの扱い方は、 Django などでも同じなので慣れておくと追々役に立つでしょう。

Pythonプログラム(web01.py) と HTMLファイル(templates/hello.html) がセット出来たら、プログラムを実行。 localhost:5000/hello にアクセスすると hello.html が読み込まれていることが確認できます。

上図のコード

【web01.py】
from flask import render_template, Flask
app = Flask(__name__)

@app.route('/hello/')
@app.route('/hello/')
def hello(name=None):
    return render_template('name.html', name=name)

【name.html】
<!doctype html>
<title>Hello from Flask</title>
{% if name %}
  <h1>Hello {{ name }}!</h1>
{% else %}
  <h1>Hello, World!</h1>
{% endif %}

次は公式ドキュメントに書かれている HTMLコードを使って、 変数を使った Routing に挑戦。 先ほどの hello.html とは違う name.html というファイルを作成し、実行。すると URL 内の "oshima" という文字が、ブラウザ上にも表示されていることが確認できます。本稿最初の方で紹介した "変数を使った Routing" とは少し違う制御文で、 HTML によって変数を管理できていることが確認できますね。

また HTMLコード 3行目から7行目では HTML内で if文を実行しています。普通 HTML 内で if文などの制御文は実行できませんが、 Flask を使うと制御可能に。一見 HTML内でも制御できるようになると便利そうですが、 Pythonで処理させること、 HTMLで処理させること、混乱しないように注意する必要が出てくるでしょう。

Flaskでファイル・アップロード

上図のコード

import os
from flask import Flask, flash, request, redirect, url_for
from werkzeug.utils import secure_filename

UPLOAD_FOLDER = '/path/to/the/uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        # check if the post request has the file part
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        # if user does not select file, browser also
        # submit an empty part without filename
        if file.filename == '':
            flash('No selected file')
            return redirect(request.url)
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return redirect(url_for('uploaded_file',
                                    filename=filename))
    return '''
    <!doctype html>
    <title>Upload new File</title>
    <h1>Upload new File</h1>
    <form method=post enctype=multipart/form-data>
      <input type=file name=file>
      <input type=submit value=Upload>
    </form>
    '''

Quickstart を進めていくと次は、 Uploading Files という項目が。こちらは Quickstart よりも専用ドキュメントの方が解りやすいので https://flask.palletsprojects.com/en/1.1.x/patterns/fileuploads/ のページに移動。

そして書かれているコードをコピペ。 5行目の UPLOAD_FOLDER でアップロードされてくるファイルの保存先を示し、 6行目の ALLOWED_EXTENSIONS で受け付けるファイルの種類を選択。ファイルの保存先がデフォルト・コードのままではよくないので以下のように変更。

上図のコード

import os
from flask import Flask, flash, request, redirect, url_for
from werkzeug.utils import secure_filename

UPLOAD_FOLDER = '/home/oshimamasara/★dev/1/flask/02/uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        # check if the post request has the file part
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        # if user does not select file, browser also
        # submit an empty part without filename
        if file.filename == '':
            flash('No selected file')
            return redirect(request.url)
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return redirect(url_for('uploaded_file',
                                    filename=filename))
    return '''
    <!doctype html>
    <title>Upload new File</title>
    <h1>Upload new File</h1>
    <form method=post enctype=multipart/form-data>
      <input type=file name=file>
      <input type=submit value=Upload>
    </form>
    '''

ファイルの保存先のコードを変更したら、次は保存先のフォルダ uploads を作成(上図参照)。これでプログラムを実行できる準備ができましたので、 localhost:5000 にアクセス。

今回のアップロードプログラムは、パソコン内のファイルにアクセスするため、ブラウザは Visual Studio Code外のブラウザで起動する必要があります。

「ファイルを選択」ボタンを押すと、自分のパソコンのファイル群が表示。適当なファイルを選択し、 「開く」ボタン。

「Upload」ボタン。

すると上図のようにエラー。ターミナル内のエラー文を確認すると、

werkzeug.routing.BuildError: Could not build url for endpoint 'uploaded_file' with values ['filename']. Did you mean 'upload_file' instead?

どうも 31行目のファイルアップロード後の処理が上手くいっていない様子。コードを確認すると uploaded_file なんてないんですね... そこで簡易的に uploaded_file を作成(下図参照)。

上図のコード

import os
from flask import Flask, flash, request, redirect, url_for
from werkzeug.utils import secure_filename

UPLOAD_FOLDER = '/home/oshimamasara/★dev/1/flask/02/uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        # check if the post request has the file part
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        # if user does not select file, browser also
        # submit an empty part without filename
        if file.filename == '':
            flash('No selected file')
            return redirect(request.url)
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return redirect(url_for('uploaded_file',
                                    filename=filename))
    return '''
    <!doctype html>
    <title>Upload new File</title>
    <h1>Upload new File</h1>
    <form method=post enctype=multipart/form-data>
      <input type=file name=file>
      <input type=submit value=Upload>
    </form>
    '''

@app.route('/uploaded')
def uploaded_file():
    return "アップロード完了"

すると今度はファイルをアップロードした後もエラーが表示されることなく、一通りの処理を実行できた事が確認できます。またアップロードしたファイルは、きちんと uploads フォルダ内に入っていますね(上図参照)。

他にも エラー文 Cookies に関する項目がありますが、今回の Flask 紹介はこのあたりまでとしておきます。

AIエンジニアに必要なスキルが身に付く

CodeCampの無料体験はこちら

まとめ

今回 Flask の公式ドキュメントに従って Flask の基本的な機能をご紹介させて頂きましたが、公式通りのコードではエラーがチラホラでましたよね。

また テンプレートのセッションでは HTML が登場し、アップロードするセッションでは "path" などのプログラミングとは直接関係ない要素も。

こうしたテキスト通りにやってもプログラムが実行できない場合、やはり Python や HTML の基礎があると 「何がいけないのか」 「何が足りないのか」 自分で考えて解決することができます。つまり "基礎" は "大事" ということ。

「Pythonの参考書は買ったんだけどな...」 「プログラミング、 コード、 自分には無理...」 と諦めモードの方、本当にそのままの自分でいいのでしょうか? ちょっとでも "プログラミング" による明るい未来を想像したのなら、もう少し頑張ってみませんか?

CodeCamp では、プログラミング初学者向けに教材を提供し、個人個人にあった方法でレッスンを実行。少しでも自分が想像した明るい未来に近づけるよう、まずは "無料体験" で、プログラミングに触れてみませんか? 全然分からなかった "コード" も先生と一緒になぞって、書いて、実行してみると、案外チョロいかもしれませんよ。

無料体験に関する詳しい情報は、 公式ページ より確認してみてください。

昨今のプログラミング・ニーズの高まりを受けて、無料体験枠が埋まっている日もあります。予め、ご了承ください。

オシママサラ
この記事を書いた人
オシママサラ
\ 無料体験開催中!/自分のペースで確実に習得!
オンライン・プログラミングレッスンNo.1のCodeCamp