Railsを使って開発をしていたが、最近Pythonを使う機会が増えてきたので、今年はPythonの軽量WebフレームワークFlaskを使ってWebサービスを開発する流れをまとめた。作ったサービスをHerokuで運用するところまでやった。作るものシンプルなメモ。本文はMarkdown記法に対応させる。使うものPyenvプロジェクト毎にPythonのバージョンを切り替えるために使用。インストール方法、設定方法は省略。3.6.3今回は、2系を使う必要性がないため、最新版の3.6.3を使用。Pyenvでインストール。Virtualenvプロジェクト単位でパッケージ群などを含むPython環境を切り替えるために使用。FlaskPython用の軽量Webフレームワーク。JinjaFlask用のHTMLテンプレートエンジンJinja2でもHAML的な構文を使えるようにするために使用。PostgreSQL最初の動作確認にはSQLiteを使用。その後、Herokuで運用するにあたってPostgreSQLに切り替える。Heroku運用はHerokuで。アカウント登録とCLIのインストールが必要。initFlaskには特にプロジェクト作成用のコマンドなどは用意されていないので、新しく空のディレクトリ一つ用意して、その中で作業をして行く。以降gitのファイル管理のコマンドについては省略。開発用Virtualenv環境を作るPyenvで作成した環境に直接パッケージをインストールしていくと、複数のプロジェクトを走らせる際に問題が起きたりするので、Virtualenvを使って環境を切り分けて開発を進めていく。新しくVirtualenv環境を作成する。venvVirtualenv環境は通常git上で管理する必要はないので、.gitignoreに登録しておく。以降、開発の際は作成したVirtualenv環境をアクティベートした上で、サーバーの起動やパッケージのインストールなどを行っていく。Worldアプリを作ってHerokuにデプロイする。flaskFlaskのインストールはpipコマンド一発。World!を表示するシンプルなプログラムを作る。World!'デコレーター@app.route()を使って、パス(/)がリクエストされた時に呼ばれる関数を紐づける。今回の設定では、(/)が呼ばれた時にhello_world()関数の返り値が画面に表示されるようになる。runコマンドで、サーバーを起動する。FLASK_APPで、Flaskアプリの実装を行ったファイルを指定する。runデバッグ用にFLASK_DEBUG=1を指定する。これを指定しないと、コードを変更しても実行コードに反映されないので不便。このオプションは本番環境では使用してはいけない。サーバーが起動したらhttp://localhost:5000/を開く。HTMLテンプレートを使うFlaskでは、HTMLテンプレートエンジンJinja2が利用できる。関数の返り値でテキストを直接返す代わりに、render_template関数を使うと、Jinja2のテンプレートを利用してレスポンスを生成できる。Jinjaを使うと、JinjaでHAML風の記法を使うことができる。Hamlish-JinjaHamlishExtensionを有効にしたjinja_optionsを持ったFlaskインスタンスを作るために、サブクラスを作る。world変数を使うrender_templateの引数で変数を渡すと、テンプレート内で{{変数名}}の形で展開できる。Worldだが、一旦ここまでをHerokuにDeployしてみる。gunicornで動作確認するFlaskアプリをHeroku上で動かすときは、gunicornをサーバーとして使用する。動作確認用に、ローカルにもgunicornをインストールする。rehashローカルでgunicornを使ってFlaskアプリを立ち上げてみる。Flaskアプリ(app.py内のapp)を引数で指定する。app:appgunicornを使う場合は8000番ポートにサーバーが起動するので、http://localhost:8000/を開いて動作確認する。runした時と同じように表示されればOK。freezeでrequirements.txtに書き出す。requirements.txtProcfileを作成し、フロントインスタンス(web)用のgunicornを使ったサーバーの起動コマンドを指定する。app:app最後にruntime.txtを作成し、そこに使用するPythonのバージョンを記述する。CLIから、新しいHerokuアプリを作成する。masterでHerokuにPushする。openコマンドで、デプロイされたアプリを開いて動作確認する。Worldアプリをデプロイできたところで、今度はデータベースを使ってみる。HerokuではSQLiteを使用できないので、PostgreSQLを使うことになるのだが、より良い理解のために素のSQLを書いてSQLiteデータベースをいじるところから順を追って動かしてみる。SQLiteデータベースのデータを表示する手始めに、SQLを書いてデータベースのテーブルの内容を表示してみる。新しくSQLiteデータベースを作成し、そこにentriesテーブルを作る。flasknote.dbentriesテーブルを作成し、そこに手動でレコードを追加する。Japan.");レコードを表示してみるTutorialの内容を元に、このテーブルの内容を表示してみる。entries').fetchall()でflasknote.dbのentriesテーブルの中身を取得している一文。Variableのgにデータベースとのコネクションを持たせ、リクエスト毎に新しいコネクションを作らないようにしていたり、アプリと同じディレクトリにあるflasknote.dbのパスを取得するための処理が入っていたりするが、これらの部分はあまり重要ではない(それに、あとで使わなくなる)ので、一旦スルーしても問題ない。取得したentriesをrender_templateの引数にわたして、テンプレート(index.haml)内でそれを表示する。}}|は所謂フィルタ。safeフィルターは、HTMLエスケープ処理をしてくれるフィルター。SQLAlchemyを使う生のSQLを書くのは、セキュリティ的にも効率的にも避けたいので、O/RマッパーであるSQLAlchemyを使う形に実装を置き換える。flask_sqlalchemyのインストールFlask用のSQLAlchemyをpipでインストール。entries=entries)sqliteのimportの代わりに、flask_sqlalchemyをimportする。SQLiteデータベースの場所は、app.config['SQLALCHEMY_DATABASE_URI']に指定する。SQLiteデータベースであることを示すスキーマsqlite:///でデータベースのパスを指定する。DBのテーブルと、Python上のモデルのO/Rマッピング用のクラスEntryを定義する。Python上でのクラスは単数形(Entry)、テーブル名は複数形(entries)を使いたかったので、__tablename__でテーブル名を明示的に指定している。その下のid、title、bodyはフィールドの型の定義。primary_keyやnullableの指定は、SQLAlchemyの機能を使ってテーブルを作成する時用の設定(後述)ブラウザで開いて、生のSQLを書いていた時同様、データを取得・表示できていればOK。投稿フォームを作ってデータを追加する表示がうまくいったので、投稿フォームを作ってデータの追加もできるようにする。HTML側にフォームを追加。%input(type="submit")受け取り用のURL(/post)を追加する。POSTメソッドに対応させる場合は、パスのパターンだけでなく、methods=['POST']を指定する必要がある。request.form['body'])をフィールドにセットする。db.sessionに追加してcommitすると、SQLが発行され、データベースに追加が行われる。処理が完了したら、redirect関数を使って一覧画面にリダイレクトする。一覧画面のURLはurl_for('リダイレクトしたいURL用の関数名')で取得。ブラウザ上で、フォームから値を入力・送信してみて、データが追加されればOK。PostgreSQLを使うHerokuではSQLiteを使うことができないので、PostgreSQLを使う形に変更する。SQLAlchemyはPostgreSQLにも対応しているため、データベースの接続先をSQLiteデータベースからPostgreSQLデータベースに変更するだけ。Herokuで動かす前に、一応ローカルのPostgreSQLデータベースを使って動作確認する。PostgreSQLデータベースの作成PostgreSQLのcreatedbコマンドで、新しいデータベースを作成する。flasknotepsycopg2のインストールSQLAlchemyでPostgreSQLを利用するために、psycopg2パッケージが別途必要になるので、pipでインストールする。psycopg2SQLAlchemyを使ってテーブルを作るSQLiteを使う際にやったように、手動でSQLを叩いてテーブルを作っても良いのだが、SQLAlchemyにはマッピングクラスの定義からテーブルを作ってくれる機能があるので、今回はそれを使ってテーブルを作ってみよう。pythonコマンドでPythonインタープリターを起動して、その中でSQLAlchemyのcreate_all()を使ってみよう。dbでapp.py内に定義したSQLAlchemyインスタンスdbをimportする。このSQLAlchemyインスタンスのcreate_all()メソッドを呼ぶと、モデル内の定義(今回の場合はEntryクラス内に記述した__tablename__やdb.Columnで指定した各フィールドの情報)を元に、SQLを発行してテーブルを作成してくれる。(対象となるデータベースは、app.pyでSQLAlchemyのインスタンスの生成前に指定したapp.config['SQLALCHEMY_DATABASE_URI']の向き先となる)動作確認サーバーを再起動して、動作確認。問題がなさそうだったら、いよいよHerokuにデプロイする。HerokuにDeployするrequirements.txtの更新SQLAlchemyなど、使用するパッケージが増えたので、最新のパッケージ一覧をrequirements.txtに書き出す。Postgresアドオンを追加する。DevデータベースURLの変更app.py内で、データベースの向き先を変更する。Postgresアドオンを追加した場合、環境変数DATABASE_URLにPostgreSQLデータベースの接続先URLがセットされるので、この値がセットされているとき(Heroku上で動作するとき)はそれを使い、セットされていないとき(ローカルでのデバッグなど)はローカルのPostgreSQLデータベースを使うようにする。デプロイいよいよソースコードをデプロイ。masterテーブルの作成HerokuのPostgreSQLデータベース上に、テーブルを作成する。ローカルで作成したとき同様、SQLAlchemyの機能を使ってテーブルを作成する。pythonでHeroku上のPythonインタープリターを起動。ローカルの時と同様のコマンドで、テーブルを作成する。openでHerokuサーバーをブラウザで開き、動作確認をする。Markdown対応データベースへの接続も含め、Heroku上で動作するようになった。このままではあまりに機能が少なすぎるので、最後におまけでMarkdown対応をしてみる。Flask-MarkdownのインストールpipでFlask-Markdownをインストールする。Flask-MarkdownMarkdownインスタンスの作成Markdownをimportし、インスタンスを作成する処理を入れる。追加...Markdown表示したい箇所でフィルターを使うEntryのbody部分をMarkdownとして表示する。使い方はいたって簡単でmarkdownフィルターを使うだけ。最後に、Bootstrapなどを使って見た目を整えたり、一旦完成。%input.btn.btn-primary.btn-block(type="submit")まとめデータベースを使ったFlaskアプリをHerokuにデプロイするところまでできた。テーブルのマイグレーションやScaffoldなど、至れり尽くせりのRailsやDjangoに比べると、手動でやらなければいけないことが多くて面倒さも感じるが、コードが短く見通しも良い。Herokuで運用できるのも素敵。統計処理や機械学習など、何かとPythonに触れる機会が多くなってきたので、Pythonに慣れる意味でも軽量なWebサービスを作る際には積極的にFlaskを試していきたいと思う。upLoginユーザーは見つかりませんでした。