目次

はじめに
本書の概要
執筆の動機
本書が対象とする読者
「Flask」とは?
アプリの全体像
準備するもの
ブラウザー上に「Hello, World」と表示する最小限のFlaskアプリを作成
第1章 ディレクトリー構成とBlueprintによる機能の分割
1.1 アプリのディレクトリー構成
1.2 Blueprintで機能を分割
1.3 Blueprintを呼び出す
1.4 各ディレクトリーの機能を定義
1.5 ブラウザーに表示される部分を作成
第2章 ログイン機能の作成
2.1 ブラウザーに表示される部分の作成
2.2 ローカル環境にPostgreSQLをインストール
2.3 データベースにユーザーテーブルを作成
2.4 アプリケーションとデータベースを連携させる
2.5 データベースをオブジェクトとして扱えるようにする
2.6 開発用の仮ユーザーを登録
2.7 ログインしなければ閲覧できない画面を指定
2.8 ログアウト機能の作成
第3章 CRUD機能の実装
3.1 HTMLの共通する部分をテンプレート化
3.2 ジョブのデータモデルを定義
3.3 各テーブルをPythonのクラスとして定義
3.4 ジョブの作成(create)機能を作成
3.5 ジョブの一覧表示(top)機能を作成
3.6 ジョブの更新(update)機能を作成
第4章 請求書発行機能を作成
4.1 請求書のテンプレートをExcelファイルで作成
4.2 ブラウザー上に表示される画面を作成
4.3 請求書発行機能を実装
4.4 ヘルパー関数writeExcelの作成
第5章 管理画面の作成
5.1 ブラウザーに表示される画面を作成
5.2 管理画面の機能を定義
第6章 デプロイ
おわりに
謝辞

はじめに

本書の概要

 本書は、Pythonでwebアプリケーションを作成するためのフレームワーク「Flask」(読み:フラスク)を使って、フリーランスのwebデザイナー向けの請求書発行アプリを作る、ハンズオンチュートリアルをご紹介します。

 お手元のPCにローカル開発環境を作り、FlaskでのHello, WorldからPostgreSQLでのデータベース作成、アプリケーションの実装まで、第1章からステップバイステップで解説しています。

 また、各章における最終段階のサンプルコードを本書のGitHubリポジトリーに公開しておりますので、サンプルコードを参考に実際にお手元の環境でコードを書きながら読み進めていただくことで、理解が一層深まるかと思います。

 ■サンプルコードはこちら

 https://github.com/outsider-kithy/invoicee-local-sample

執筆の動機

 筆者はフリーランスでwebデザインをしています。毎月複数の案件について、当月作業した分をリストアップし、値段を決め、一覧にまとめた請求書をクライアントに発行するという業務が発生するのですが、「これをExcelなどの表計算ソフトで管理するのは大変だな…」という思いがありました(フリーランスのプログラマーやデザイナーの方は共感していただけるのではないでしょうか…)。

 そこで、作業内容をwebブラウザーから登録し、月末にボタンひとつで請求書を発行できるアプリケーションの作成を思い立ちました。

 本書で作成する請求書発行アプリは、私が日々の業務で実際に使用しているアプリのコアとなる機能を抜粋し、簡略化したバージョンになります。

 私自身、このアプリを使用することで、毎月月末に1日程度かけて行っていたExcelでの請求書発行業務が、webブラウザーでワンクリックの作業で済むようになり、30分程度で完了するようになりました。

 さらに、本アプリのような「データベースのCRUD操作」と「ファイルI/O」をアプリケーションで実装する、というプログラミング体験は、PythonやFlaskに限らず、さまざまな言語やフレームワークでも応用が利くたくさんの知見を、プログラミング初心者であった筆者に与えてくれました。

 「Pythonの基礎は勉強したけど、アプリケーションの開発はどうやったらいいかわからない…」

 「Flaskを触ってみたいけど、どんなアプリが作れるのか全体像を知りたい」

 といったプログラミング初級〜中級者の方に、本書がお役に立てれば幸いです。

 また、本書で紹介する方法はFlaskでwebアプリケーションを作成する基本的なものになりますので、このアプリを拡張して独自の機能を追加したり、このアプリを応用してPythonが得意とする流行りの機械学習やAIを用いたアプリケーションを作成したりと、さまざまな用途に展開することも可能です。ご自身の目的とスキルに応じてぜひご活用いただければと思います。

本書が対象とする読者

 ・請求書発行業務をお金をかけずに効率化したいプログラマー・デザイナーの方

 ・webサイト制作やwebアプリケーション制作に少しでも携わったことがある方

 ・Pythonの基本的な書き方がわかる方

 ・SQLの基礎がわかる方

 ・アプリケーションの開発を通してレベルアップしたいプログラミング初級〜中級者の方

 ・Flaskでのアプリケーションの全体像をざっくりつかみたい方

「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を備えています。

図1: ログイン画面
図2: ユーザー新規登録画面
図3: ジョブ一覧画面
図4: 新規ジョブ作成画面
図5: ジョブの更新画面
図6: 請求書発行画面
図7: 管理画面

 各画面の関係性は、次の図のような構成になっており、グローバルナビからそれぞれの画面に遷移できます。

図8: 画面遷移図

 本アプリでは、「ジョブ」という概念で案件にまつわるデータを管理します。それぞれのジョブには「クライアント」「価格」「税率」「ツール名」「作業内容」といったデータが紐づけられて、データベースに登録されています。そして、請求書発行時にそれらのデータをExcelファイルの適切な箇所に書き込んで出力する、という仕組みになっています。

 そして、本アプリの請求書発行画面のラジオボタンでジョブを選択し、「請求書を出力」ボタンを押すと、下記のようなExcel形式の請求書が発行される仕組みになっています。

図9: 請求書のテンプレートファイル

 このうち、ジョブを管理するデータベースについては第3章で、請求書のExcelファイルへの書き込みについては第4章で詳しく解説します。

準備するもの

 本アプリの開発はVS Codeを使用しています。VS Code以外でもエディターと、Macユーザーであればターミナル、WindowsユーザーであればPowerShellがあれば大丈夫です。

 本書で作成するアプリケーションは、下記のバージョンにおける動作を確認しています。

 ・Python 3.8.9

 ・pip 20.2.3

 ・Flask 2.2.2

Macの場合

 Macをお使いの方は、あらかじめPython2系がインストールされているかと思いますが、Python3系がインストールされていない場合は、事前にこちらのサイトからPython3.8.9をインストールしておいてください。

 https://www.python.org/downloads/macos/

 ターミナルで下記のコマンドを実行し、「Python 3.8.9」と表示されればインストール完了です。

Python3 -V

# Python 3.8.9

Windowsの場合

 こちらのサイトからPython3.8.9をインストールしておいてください。

 https://www.python.org/downloads/windows/

 PowerShellで下記のコマンドを実行し、「Python 3.8.9」と表示されればインストール完了です。

Python -V

# Python 3.8.9

 準備ができたら、まずはFlaskを使ってブラウザー上に「Hello, World」と表示するだけのミニマムなアプリケーションを作成してみましょう。サンプルコードはchap01になります。

ブラウザー上に「Hello, World」と表示する最小限のFlaskアプリを作成

プロジェクトフォルダー「chap01」を作成

 ターミナル/PowerShellで以下のシェルを実行して、chap01フォルダーを作成します。

mkdir chap01

cd chap01

仮想環境「.venv」を作成

 お手元のローカルPCでアプリケーションを作成する場合、PCに直接Pythonのライブラリーをインストールするのではなく、「仮想環境」を作成して、そこにアプリケーションに必要なライブラリーをインストールしていくという方法が一般的です。というのも、ライブラリーによっては対応しているPythonのバージョンが決まっているので、「開発中のアプリ以外のプログラムのライブラリーの依存関係上、欲しいバージョンのライブラリーがインストールできない...」とか「ローカル環境では動いたのに、本番環境だとエラーが出た...」といった問題を防ぐことができるからです。

 今回も、プロジェクトフォルダー「chap01」内に仮想環境「.venv」を作成し、そこに必要なライブラリーをインストールしていきます。

Macの場合

 ターミナルで下記のコマンドを入力して、仮想環境「.venv」を作成します。

#仮想環境「.venv」を作成

python3 -m venv .venv

 chap01ディレクトリー内に、.venvフォルダーが作成されたかと思います。次に、ローカル環境のPythonから、仮想環境「.venv」をアクティベートして、環境の切り替えを行います。

#仮想環境をアクティベート

source .venv/bin/activate

 ターミナルのプロンプトの先頭が(.venv) $ になれば、仮想環境を有効化できています。

Windowsの場合

 chap01ディレクトリーにいることを確認した上で、PowerShellで以下のコマンドを実行し、仮想環境.venvを作成します。

#実行ポリシーを変更

Set-ExecutionPolicy RemoteSigned CurrentUser

#仮想環境「.venv」を作成

python -m venv .venv

 chap01ディレクトリー内に、.venvフォルダーが作成されたら、PowerShell上で以下のコマンドを実行して仮想環境を有効化します。

.venv\Scripts\Activate.ps1

 PowerShellのプロンプトの先頭が(.venv)になれば、仮想環境を有効化できています。

 開発を中断するなど、仮想環境を無効化する場合は、ターミナル/PowerShellに

deactivate

 と入力します。プロンプトの先頭から(.venv)が消えたら、無効化できています。

Flaskをインストール

 それでは、新しく作成した仮想環境「.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

ブラウザーで「Hello, World!」と返すだけの最小限のアプリを作る

 Flaskがインストールできたところで、ブラウザーに「Hello, World!」と表示するだけの最小限のアプリを作成してみましょう。chap01ディレクトリーにapp.pyファイルを作成し、以下を記述します。このapp.pyファイルが、Flaskアプリケーションの本体のプログラムとなり、次章以降もアプリケーションの基本的な機能はこのapp.pyに追加していく形になります。

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から、それぞれの環境変数を定義します。

Macの場合

(.venv) $ export FLASK_APP=app.py

(.venv) $ export FLASK_ENV=development

Windowsの場合

(.venv) $env:FLASK_APP=app.py

(.venv) $env:FLASK_ENV=development

自動で環境変数を読み込む設定に変更

 しかし、毎回環境変数をターミナル/PowerShellから設定するのは面倒なので、.envファイルを作成してそこに環境変数を定義しておき、アプリケーションの起動時に自動で読み込んでくる設定にしておきます。そのためのライブラリーpython-dotenvを仮想環境にインストールします。

 (.venv) $ pip install python-dotenv

 chap01ディレクトリー内に.envファイルを作成して、環境変数を定義します。

.env

 1: FLASK_APP=app.py
 2: FLASK_ENV=development

 これで、Flaskアプリを起動する準備が整いました。

Flaskアプリを起動

 ターミナル/PowerShellで、以下を実行します。

(.venv) $ flask run

 アプリが正常に起動すると、ターミナルに

 Running on http://127.0.0.1:5000

 と表示されるので、webブラウザーでhttp://127.0.0.1:5000にアクセスしてみてください。

図10: Hello, World

 と表示されていれば成功です。

 ここまでが、Flaskの最小限のアプリを立ち上げるまでの流れです。今後の開発中も、

 1. (Macの場合は)source .venv/bin/activate

 (Windowsの場合は).venv\Scripts\Activate.ps1

 で仮想環境をアクティベートする

 2. プログラムを書く

 3. flask runでアプリを起動する

 4. 仮想環境を無効化する場合はdeactivate

 の繰り返しで、ブラウザー上での挙動を確認しながら開発を進めていくのが基本的な流れとなります。

 それでは、次章から実際にアプリケーションを作成していきましょう。

第1章 ディレクトリー構成とBlueprintによる機能の分割

1.1 アプリのディレクトリー構成

 これから作成するアプリケーションは、最終的に以下のようなディレクトリー構成になります。

図1.1: ディレクトリー構成
図1.2: ディレクトリー構成(続き)

 前章でリストアップした「ログイン画面」や「新規ジョブ作成画面」など、それぞれの画面に対応するディレクトリーがlogincreateとなります。各ディレクトリー内にそれぞれの画面の機能を記述するviews.pyファイルと、実際にレンダリングされるindex.htmlファイルがtemplatesディレクトリーの中に入っています。それら全ての画面の機能がapp.pyに集約されて、app.pyをエントリーポイントとしてアプリケーションが起動する、というイメージです。では、初めにapp.pyファイルから更新していきます。なお、本章の最終バージョンのコードは、サンプルコードのchap02ディレクトリーにあります。

1.2 Blueprintで機能を分割

 今回のアプリのように、ログインやジョブ一覧の表示、ジョブの新規作成など、アプリケーション内で複数の処理を行う場合、ブラウザーでの1画面ごとにひとつの処理を実行できるようにしておくと、ユーザーにとっても開発者にとってもわかりやすいアプリケーションになります。このようなアプリケーションの機能の分割をFlaskで実現するためには、Blueprintというライブラリーを使用します。app.pyを以下のように書き換えます。

1.3 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ファイルを作成し、ここに各画面の機能を定義していきます。

1.4 各ディレクトリーの機能を定義

 最初に、loginディレクトリーの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)

1.5 ブラウザーに表示される部分を作成

 続いて、/loginルートでアクセスしてきたときに、ブラウザー上にレンダリングされるhtmlファイルを/login/templates/login/index.htmlファイルとして作成します。

 ここで注意しなければならないのが、templatesディレクトリー配下にloginディレクトリーを一度挟むという点です(まどろっこしいのですが、こうしないとFlaskが正しくパスを認識できず、htmlファイルがレンダリングされません...)。

login/templates/login/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>

 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画面がレンダリングされていれば成功です。

図1.3: ログイン画面

 基本的な流れは以上です。残りのregister,top画面も同様に、views.pyindex.htmlファイルを作成していきます。

register/views.py

 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")

register/templates/login/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画面も同様に

app.py

 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/

図1.4: 新規ユーザー登録画面

 http://127.0.0.1:5000/top/

図1.5: トップ画面

 それぞれの画面が表示されれば、Blueprintでの分割が完了しています。

 次章では、ログイン機能とユーザー新規登録機能を実装していきます。

試し読みはここまでです。
この続きは、製品版でお楽しみください。