本書は、Pythonでwebアプリケーションを作成するためのフレームワーク「Flask」(読み:フラスク)を使って、フリーランスのwebデザイナー向けの請求書発行アプリを作る、ハンズオンチュートリアルをご紹介します。
お手元のPCにローカル開発環境を作り、FlaskでのHello, WorldからPostgreSQLでのデータベース作成、アプリケーションの実装まで、第1章からステップバイステップで解説しています。
また、各章における最終段階のサンプルコードを本書のGitHubリポジトリーに公開しておりますので、サンプルコードを参考に実際にお手元の環境でコードを書きながら読み進めていただくことで、理解が一層深まるかと思います。
■サンプルコードはこちら
筆者はフリーランスでwebデザインをしています。毎月複数の案件について、当月作業した分をリストアップし、値段を決め、一覧にまとめた請求書をクライアントに発行するという業務が発生するのですが、「これをExcelなどの表計算ソフトで管理するのは大変だな…」という思いがありました(フリーランスのプログラマーやデザイナーの方は共感していただけるのではないでしょうか…)。
そこで、作業内容をwebブラウザーから登録し、月末にボタンひとつで請求書を発行できるアプリケーションの作成を思い立ちました。
本書で作成する請求書発行アプリは、私が日々の業務で実際に使用しているアプリのコアとなる機能を抜粋し、簡略化したバージョンになります。
私自身、このアプリを使用することで、毎月月末に1日程度かけて行っていたExcelでの請求書発行業務が、webブラウザーでワンクリックの作業で済むようになり、30分程度で完了するようになりました。
さらに、本アプリのような「データベースのCRUD操作」と「ファイルI/O」をアプリケーションで実装する、というプログラミング体験は、PythonやFlaskに限らず、さまざまな言語やフレームワークでも応用が利くたくさんの知見を、プログラミング初心者であった筆者に与えてくれました。
「Pythonの基礎は勉強したけど、アプリケーションの開発はどうやったらいいかわからない…」
「Flaskを触ってみたいけど、どんなアプリが作れるのか全体像を知りたい」
といったプログラミング初級〜中級者の方に、本書がお役に立てれば幸いです。
また、本書で紹介する方法はFlaskでwebアプリケーションを作成する基本的なものになりますので、このアプリを拡張して独自の機能を追加したり、このアプリを応用してPythonが得意とする流行りの機械学習やAIを用いたアプリケーションを作成したりと、さまざまな用途に展開することも可能です。ご自身の目的とスキルに応じてぜひご活用いただければと思います。
・請求書発行業務をお金をかけずに効率化したいプログラマー・デザイナーの方
・webサイト制作やwebアプリケーション制作に少しでも携わったことがある方
・Pythonの基本的な書き方がわかる方
・SQLの基礎がわかる方
・アプリケーションの開発を通してレベルアップしたいプログラミング初級〜中級者の方
・Flaskでのアプリケーションの全体像をざっくりつかみたい方
webアプリケーションを作成するとき、クライアント・サーバー間のやりとりやデータベース操作など、どんなwebアプリケーションでも共通して必要になる機能があります。そのような「よくある処理」をあらかじめ作成し、フルスクラッチで作るよりも少ない手順で呼び出せるようにし、それらを組み合わせることで独自の機能も簡単に作成できるような枠組みのことをフレームワークといいます。FlaskはPythonでwebアプリケーションを作成するための、軽量かつシンプルなオープンソースのフレームワークです。Flaskを利用して作成されたwebアプリケーションは数多くあり、代表的なところだとNetflixやPinterestなどが有名です。
公式ドキュメント(英語) https://flask.palletsprojects.com/en/2.3.x/
日本語版 https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/index.html
それでは、作成するアプリケーションの全体像から確認していきます。
本書で作成する請求書発行アプリ「invoicee」は、下記の機能を担う画面で成り立っています。
・ログイン画面
・ユーザー新規登録画面
・ジョブ一覧画面
・新規ジョブ作成画面
・ジョブの更新画面
・請求書発行画面
・管理画面
・(ログアウト画面)
それぞれの画面は、下記のようなUIを備えています。
各画面の関係性は、次の図のような構成になっており、グローバルナビからそれぞれの画面に遷移できます。
本アプリでは、「ジョブ」という概念で案件にまつわるデータを管理します。それぞれのジョブには「クライアント」「価格」「税率」「ツール名」「作業内容」といったデータが紐づけられて、データベースに登録されています。そして、請求書発行時にそれらのデータをExcelファイルの適切な箇所に書き込んで出力する、という仕組みになっています。
そして、本アプリの請求書発行画面のラジオボタンでジョブを選択し、「請求書を出力」ボタンを押すと、下記のようなExcel形式の請求書が発行される仕組みになっています。
このうち、ジョブを管理するデータベースについては第3章で、請求書のExcelファイルへの書き込みについては第4章で詳しく解説します。
本アプリの開発はVS Codeを使用しています。VS Code以外でもエディターと、Macユーザーであればターミナル、WindowsユーザーであればPowerShellがあれば大丈夫です。
本書で作成するアプリケーションは、下記のバージョンにおける動作を確認しています。
・Python 3.8.9
・pip 20.2.3
・Flask 2.2.2
Macをお使いの方は、あらかじめPython2系がインストールされているかと思いますが、Python3系がインストールされていない場合は、事前にこちらのサイトからPython3.8.9をインストールしておいてください。
https://www.python.org/downloads/macos/
ターミナルで下記のコマンドを実行し、「Python 3.8.9」と表示されればインストール完了です。
Python3 -V
# Python 3.8.9
こちらのサイトからPython3.8.9をインストールしておいてください。
https://www.python.org/downloads/windows/
PowerShellで下記のコマンドを実行し、「Python 3.8.9」と表示されればインストール完了です。
Python -V
# Python 3.8.9
準備ができたら、まずはFlaskを使ってブラウザー上に「Hello, World」と表示するだけのミニマムなアプリケーションを作成してみましょう。サンプルコードはchap01になります。
ターミナル/PowerShellで以下のシェルを実行して、chap01フォルダーを作成します。
mkdir chap01
cd chap01
お手元のローカルPCでアプリケーションを作成する場合、PCに直接Pythonのライブラリーをインストールするのではなく、「仮想環境」を作成して、そこにアプリケーションに必要なライブラリーをインストールしていくという方法が一般的です。というのも、ライブラリーによっては対応しているPythonのバージョンが決まっているので、「開発中のアプリ以外のプログラムのライブラリーの依存関係上、欲しいバージョンのライブラリーがインストールできない...」とか「ローカル環境では動いたのに、本番環境だとエラーが出た...」といった問題を防ぐことができるからです。
今回も、プロジェクトフォルダー「chap01」内に仮想環境「.venv」を作成し、そこに必要なライブラリーをインストールしていきます。
ターミナルで下記のコマンドを入力して、仮想環境「.venv」を作成します。
#仮想環境「.venv」を作成
python3 -m venv .venv
chap01ディレクトリー内に、.venvフォルダーが作成されたかと思います。次に、ローカル環境のPythonから、仮想環境「.venv」をアクティベートして、環境の切り替えを行います。
#仮想環境をアクティベート
source .venv/bin/activate
ターミナルのプロンプトの先頭が(.venv) $ になれば、仮想環境を有効化できています。
chap01ディレクトリーにいることを確認した上で、PowerShellで以下のコマンドを実行し、仮想環境.venvを作成します。
#実行ポリシーを変更
Set-ExecutionPolicy RemoteSigned CurrentUser
#仮想環境「.venv」を作成
python -m venv .venv
chap01ディレクトリー内に、.venvフォルダーが作成されたら、PowerShell上で以下のコマンドを実行して仮想環境を有効化します。
.venv\Scripts\Activate.ps1
PowerShellのプロンプトの先頭が(.venv)になれば、仮想環境を有効化できています。
開発を中断するなど、仮想環境を無効化する場合は、ターミナル/PowerShellに
deactivate
と入力します。プロンプトの先頭から(.venv)が消えたら、無効化できています。
それでは、新しく作成した仮想環境「.venv」に、Flaskをインストールします。仮想環境を有効化した状態で、以下を実行します。
(.venv) $ pip install flask
pip listコマンドで、インストールされたパッケージ一覧を確認します。
(.venv) $ pip list
ターミナルに、以下のようにパッケージ一覧が表示されていればOKです。
Package Version
------------------ -------
blinker 1.6.2
click 8.1.3
Flask 2.3.2
importlib-metadata 6.6.0
itsdangerous 2.1.2
Jinja2 3.1.2
MarkupSafe 2.1.3
pip 20.2.3
setuptools 49.2.1
Werkzeug 2.3.6
zipp 3.15.0
Flaskがインストールできたところで、ブラウザーに「Hello, World!」と表示するだけの最小限のアプリを作成してみましょう。chap01ディレクトリーにapp.pyファイルを作成し、以下を記述します。このapp.pyファイルが、Flaskアプリケーションの本体のプログラムとなり、次章以降もアプリケーションの基本的な機能はこのapp.pyに追加していく形になります。
1: from flask import Flask
2:
3: app = Flask(__name__)
4:
5: @app.route("/")
6: def index():
7: return "Hello, World"
8:
9: if __name__=="__main__":
10: app.run()
ただし、app.pyファイルを作成しただけでは、アプリケーションは起動しません。Flaskアプリをローカルで起動するためには、
・FLASK_APP
・FLASK_ENV
というふたつの変数を設定します。ターミナル/PowerShellから、それぞれの環境変数を定義します。
(.venv) $ export FLASK_APP=app.py
(.venv) $ export FLASK_ENV=development
(.venv) $env:FLASK_APP=app.py
(.venv) $env:FLASK_ENV=development
しかし、毎回環境変数をターミナル/PowerShellから設定するのは面倒なので、.envファイルを作成してそこに環境変数を定義しておき、アプリケーションの起動時に自動で読み込んでくる設定にしておきます。そのためのライブラリーpython-dotenvを仮想環境にインストールします。
(.venv) $ pip install python-dotenv
chap01ディレクトリー内に.envファイルを作成して、環境変数を定義します。
1: FLASK_APP=app.py
2: FLASK_ENV=development
これで、Flaskアプリを起動する準備が整いました。
ターミナル/PowerShellで、以下を実行します。
(.venv) $ flask run
アプリが正常に起動すると、ターミナルに
Running on http://127.0.0.1:5000
と表示されるので、webブラウザーでhttp://127.0.0.1:5000にアクセスしてみてください。
と表示されていれば成功です。
ここまでが、Flaskの最小限のアプリを立ち上げるまでの流れです。今後の開発中も、
1. (Macの場合は)source .venv/bin/activate、
(Windowsの場合は).venv\Scripts\Activate.ps1
で仮想環境をアクティベートする
2. プログラムを書く
3. flask runでアプリを起動する
4. 仮想環境を無効化する場合はdeactivate
の繰り返しで、ブラウザー上での挙動を確認しながら開発を進めていくのが基本的な流れとなります。
それでは、次章から実際にアプリケーションを作成していきましょう。
これから作成するアプリケーションは、最終的に以下のようなディレクトリー構成になります。
前章でリストアップした「ログイン画面」や「新規ジョブ作成画面」など、それぞれの画面に対応するディレクトリーがloginやcreateとなります。各ディレクトリー内にそれぞれの画面の機能を記述するviews.pyファイルと、実際にレンダリングされるindex.htmlファイルがtemplatesディレクトリーの中に入っています。それら全ての画面の機能がapp.pyに集約されて、app.pyをエントリーポイントとしてアプリケーションが起動する、というイメージです。では、初めにapp.pyファイルから更新していきます。なお、本章の最終バージョンのコードは、サンプルコードのchap02ディレクトリーにあります。
今回のアプリのように、ログインやジョブ一覧の表示、ジョブの新規作成など、アプリケーション内で複数の処理を行う場合、ブラウザーでの1画面ごとにひとつの処理を実行できるようにしておくと、ユーザーにとっても開発者にとってもわかりやすいアプリケーションになります。このようなアプリケーションの機能の分割をFlaskで実現するためには、Blueprintというライブラリーを使用します。app.pyを以下のように書き換えます。
1: from flask import Flask
2:
3: def create_app():
4: app = Flask(__name__)
5:
6: #login画面
7: from login import views as login_views
8: app.register_blueprint(login_views.login, url_prefix="/login")
9:
10: # その他の画面も後ほど同様にimportします
11: return app
create_app関数はログイン画面やジョブの一覧画面など、それぞれの画面が持つ機能を個別にimportしています。Blueprintのregister_blueprintメソッドの第一引数にimportしたい機能のインスタンスを、第二引数にブラウザーからアクセスする際のルートをurl_prefix="/loginのように指定します(この時点では、各ディレクトリーのviews.pyファイルもtemplatesも作成していないので、flask runしてもエラーになります)。
#register_blueprintメソッド
app.register_blueprint(インポートしたい機能のインスタンス, ブラウザーからアクセスする際のルート)
次に、それぞれのディレクトリーにviews.pyファイルを作成し、ここに各画面の機能を定義していきます。
最初に、loginディレクトリーのviews.pyを作成します。
1: from flask import Blueprint, render_template
2:
3: login = Blueprint(
4: "login",
5: __name__,
6: template_folder="templates",
7: )
8:
9: @login.route("/")
10: def index():
11: # loginルートの機能を記載
12: return render_template("login/index.html")
login/views.pyでは、ログイン画面でどんな処理を行うのかを定義しています。Blueprintモジュールをimportし、loginという名前でBlueprintクラスをインスタンス化します(このインスタンスが先程app.pyでimportしているインスタンスです)。このloginが、ログイン画面の機能を担うオブジェクトとなります。
さらに、デコレーター@login.route("/")以下でindex関数を定義し、この関数内に画面毎の具体的な処理を書いていきます。ログイン画面の場合、/loginにアクセスしてきた際に、ブラウザー上にユーザー名とパスワードを入力するフォームを表示させたいので、レンダリングされるhtmlファイルをrender_template関数で指定します。render_template関数は引数にレンダリングしたいhtmlファイルまでのパスを渡します。
#render_template関数
#htmlに渡したい値がある場合は、第2引数に指定
render_template("レンダリングするhtmlファイルまでのパス",value=hoge)
続いて、/loginルートでアクセスしてきたときに、ブラウザー上にレンダリングされるhtmlファイルを/login/templates/login/index.htmlファイルとして作成します。
ここで注意しなければならないのが、templatesディレクトリー配下にloginディレクトリーを一度挟むという点です(まどろっこしいのですが、こうしないとFlaskが正しくパスを認識できず、htmlファイルがレンダリングされません...)。
1: <!DOCTYPE html>
2: <html lang="ja">
3: <head>
4: <meta charset="utf-8">
5: <title>ログイン画面</title>
6: <link rel="stylesheet" href="{{url_for('static',filename='style.css')}}">
7: </head>
8: <body>
9: <h1>ログイン画面</h1>
10: </body>
11: </html>
CSSでデザインを当てたい場合は、static/css/style.cssファイルにスタイルを記述し、<link rel="stylesheet" href="{{url_for('static',filename='style.css')}">}で読み込みます。CSSによるUIデザインは本書の範囲外となりますので、サンプルコードのCSSをそのままご利用いただくのが早いかと思います。もちろん、ご自身でお好みのCSSを書いて、独自のUIデザインを実装していただいても大丈夫です。
では、htmlファイルが用意できた状態でflask runしてアプリケーションを起動します。ブラウザーでhttp://127.0.0.1:5000/login/にアクセスし、login画面がレンダリングされていれば成功です。
基本的な流れは以上です。残りのregister,top画面も同様に、views.pyとindex.htmlファイルを作成していきます。
1: from flask import Blueprint, render_template
2: register = Blueprint(
3: "register",
4: __name__,
5: template_folder="templates",
6: )
7:
8: @register.route("/")
9: def index():
10: # registerルートの機能を記載
11: return render_template("register/index.html")
1: <!DOCTYPE html>
2: <html lang="ja">
3: <head>
4: <meta charset="utf-8">
5: <title>ユーザー登録画面</title>
6: <link rel="stylesheet" href="{{url_for('static',filename='style.css')}}">
7: </head>
8: <body>
9: <h1>ユーザー登録画面</h1>
10: </body>
11: </html>
※top画面も同様に
1: #以下を追加
2: #register画面
3: from register import views as register_views
4: app.register_blueprint(register_views.register, url_prefix="/register")
5:
6: #top画面
7: from top import views as top_views
8: app.register_blueprint(top_views.top, url_prefix="/top")
すべての画面を登録したら、flask runでアプリを起動して
http://127.0.0.1:5000/register/
http://127.0.0.1:5000/top/
それぞれの画面が表示されれば、Blueprintでの分割が完了しています。
次章では、ログイン機能とユーザー新規登録機能を実装していきます。