Python3 + Flask + wfastcgi のアプリを、IISでホストする

以前調べた範囲では、Python3 + Djangoでは、MS Accessをバックエンドにするのは難しいものの、SQLAlchemy + pyodbc であれば、比較的楽にPython3からMS Accessへと接続できそうだとわかりました。
Python3を使ってMS Access(*.accdb)へ接続してみた - メモ的な思考的な

 
また、wfastcgiというライブラリを使うことで、WSGIアプリをIISでホストできることが分かったものの、Djangoだけしか試せていませんでした。
Django + IIS + wfastcgiで静的ファイル(CSS, JavaScriptなど)を配信する - メモ的な思考的な

 
そこで今回、それらを組み合わせた

  • Flask + SQLAlchemy + pyodbc を使ったWebアプリ
    • データベースとして、MS Accessを使用
  • wfastcgiを使った、FlaskのIISホスト

を試してみました。

なお、MS AccessがなくてもFlaskをIISでホストできるため、記事のタイトルからは意図的にMS Accessを外してあります。

  

環境

  • IIS 7.0
    • 64bit OS
  • データベース
  • Access Database Engine 2010 再頒布可能コンポーネント (32bit版)
    • pyodbcで接続する時に必要
  • Python 3.4.4 32bit版
    • アプリ内で使うpyodbcの都合上、3.4系を使います*1
  • Flask 0.10.1
  • SQLAlchemy 1.0.12
  • sqlalchemy-access 0.8.dev0
  • pyodbc 3.0.10
  • アプリ用のディレクトリ
    • D:\flask_iisの下

 

Access Database Engineのインストール

今回はデータベースとしてAccessを使うので、以下よりAccess Database Engineをダウンロード・インストールします。
Download Microsoft Access データベース エンジン 2010 再頒布可能コンポーネント from Official Microsoft Download Center

今回のPython3.4は32bit版なので、Access Database Engineも32bit版(AccessDatabaseEngine.exe)を使います。

 

Flaskアプリの動作環境を作成

今回は以下のアプリを使います。
thinkAmi-sandbox/Flask_ms_access_with_iis_sample

Flaskアプリの仕様を載せると長くなりそうなので、後述することにします。

コマンドプロンプトなどから、以下の作業を行います。

# GitHubにあるソースコードを、`d:\flask_iis`へと入れておく

# virtualenv環境作成からライブラリのインストールまで
d:\flask_iis>virtualenv -p c:\python34\python.exe env

d:\flask_iis>env\Scripts\activate

(env) d:\flask_iis>pip install -r requirements.txt

(env) d:\flask_iis>pip list
Flask (0.10.1)
itsdangerous (0.24)
Jinja2 (2.8)
MarkupSafe (0.23)
pip (8.1.1)
pyodbc (3.0.10)
setuptools (20.4)
SQLAlchemy (1.0.12)
sqlalchemy-access (0.8.dev0)
Werkzeug (0.11.5)
wfastcgi (2.2)
wheel (0.29.0)

# 動作確認(http://127.0.0.1:5000/)
(env) d:\flask_iis>python server.py

# 確認できたら、`Ctrl + C`で一度停止する

 
作成したディレクトリ構成は、以下の通りです。

d:\flask_iis
├── env\ (virtualenv環境)
│    └── ...
├── static\  (CSS等のファイルを入れるディレクトリ)
│    └── style.css
├── templates\  (FlaskアプリのJinja2テンプレートディレクトリ)
│    └── index.html
├── requirements.txt
├── sample.accdb (MS Accessデータベース)
├── sample.xml (Flaskで表示するxmlファイル)
├── server.py (Flaskアプリ本体)
└── web.config (wfastcgiによるIISホスト用の設定ファイル)

 
また、MS Access(sample.accdb)のテーブル(Item)は、以下の通りです。

列名
ID オートナンバー
item_name テキスト

 
設定値は以下の通りです。

ID item_name
1 ほげ
2 foo

 

IISの設定

IISのインストール

IIS + CGIは、以下を参考にインストールします。
CGI : The Official Microsoft IIS Site

また、IIS7.0でwfastcgiを使う場合はKB980363が必要になりますので、IISのインストール後にパッチを適用します。詳細は過去記事に書きました。
IIS7.0 + Python3 + wfastcgi 構成のWSGIアプリ作成時に発生したエラーのメモ - メモ的な思考的な

 

Webサイトの追加

今回はGUIで設定するため、IISマネージャを起動します。

左ペインのサーバ名(http://localhost/)を右クリック、Webサイトの追加を選択します。

以下の内容を入力します。

項目
サイト名 Flask wfastcgi
コンテンツディレクトリ - 物理パス D:\flask_iis
バインド - ポート 9753 (任意)

 
なお、この時点でhttp://localhost:9753/にアクセスすると、

HTTP エラー 403.14 - Forbidden

Web サーバーは、このディレクトリの内容の一覧を表示しないように構成されています。

とブラウザに表示されます。

 

wfastcgiの設定

wfastcgiのPyPIページにある通り、wfastcgi-enableを実行します。
wfastcgi 2.2 : Python Package Index

(env) d:\flask_iis>wfastcgi-enable
構成変更を構成コミット パス "MACHINE/WEBROOT/APPHOST" の "MACHINE/WEBROOT/APPHOST" のセクション "system.webServer/fastCgi" に適用しました
"d:\flask_iis\env\scripts\python.exe|d:\flask_iis\env\lib\site-packages\wfastcgi.py" can now be used as a FastCGI script processor

 

web.configの作成

一番悩んだのがweb.configの設定ですが、今回は以下の通りとしました。

WSGI_HANDLER

wfastcgiのPyPIでは、設定内容について

This is a Python name that evaluates to the WSGI application object

と書かれていました。

 
設定内容の形式は、<Pythonファイル名>.<WSGIオブジェクト>となるようです。

今回のFlaskアプリは

  • Pythonファイル名
    • app = Flask(__name__)のあるファイル (server.py)
  • WSGIオブジェクト
    • 上記のapp変数

であったため、server.appを指定しました。

 
なお、同じくWSGIアプリケーションであるBottleもIISでホストできそうですが、

  • IISに対応したBottleアプリの作り方
  • その時のWSGI_HANDLERの設定内容

が分からない状況なので、今は試すことができていません。ご存じの方がいれば、教えていただけるとありがたいです。

 

PYTHONPATH

特に今回は値を指定しませんでしたが、環境に応じて設定します。

 

scriptProcessor

Djangoの時と同様、wfastcgi-enableの結果をそのままコピペします。

 
ここを踏まえた、最終的な結果は以下のような内容となりました。これをD:\flask_iis\web.configとして作成します。

<configuration>
  <appSettings>
    <add key="WSGI_HANDLER" value="server.app" />
    <add key="PYTHONPATH" value="" />
  </appSettings>
  <system.webServer>
    <handlers>
        <add name="Python FastCGI" path="*" verb="*" modules="FastCgiModule" scriptProcessor="d:\flask_iis\env\scripts\python.exe|d:\flask_iis\env\lib\site-packages\wfastcgi.py" resourceType="Unspecified" requireAccess="Script" />
    </handlers>
  </system.webServer>
</configuration>

 

ファイアウォールの設定

セキュリティが強化されたWindowsファイアウォールから、使用するTCPポート9753を開けます。

項目
規則の種類 ポート
プロトコルおよびポート - 規則 TCP
プロトコルおよびポート - 特定のローカルポート 9753
操作 接続を許可する
プロファイル 今回は、すべてにチェックを入れる
名前 Inbound for Flask app

 

動作確認

http://<ipアドレス>:9753にアクセスし、動作を確認しました。

 

Flaskアプリの仕様

Flask公式ページにあるHello Worldアプリでも良かったのですが、Flaskアプリの作り方を知る良い機会だったので、以下の仕様としました。

  • GET / でJinja2テンプレートのフォームを表示
  • POST /で、フォームで入力した値を元に、Accessからデータを取得し、テンプレート中の変数に反映
  • GET /xmlで、用意したxmlファイルをそのまま表示

 
作る時に悩んだ内容は、以下にまとめておきます。

 

Flaskまわり

 

Jinja2テンプレートまわり

FlaskでHTMLを表示するためのテンプレートとして、Jinja2を使いました。

  • テンプレートは、templatesディレクトリの下に置く
    • 今回は、D:\flask_iis\templates\index.html
  • テンプレート内でCSSを参照するには、<link ... href="{{ url_for(<ファイルがあるディレクトリ名>, filename=<CSSファイル名>) }}"/> のように書く
  • テンプレートで変数を扱う(ここでは、変数message)
    • Flaskでrender_template("index.html", message=None)のようにテンプレートへ渡す
    • テンプレートで{{ message }}のように参照する
  • テンプレートでNoneかどうかを判定する

 

SQLAlchemyまわり

 

requirements.txtまわり
  • Bitbucketなどで公開されているzipをpipでinstallしたい場合は、そのまま書く
    • https://bitbucket.org/zzzeek/sqlalchemy-access/get/default.zip

 

ソースコード

再掲となりますが、GitHubに上げてあります。
thinkAmi-sandbox/Flask_ms_access_with_iis_sample

*1:Python3.5でpyodbcを使う場合は、前回の記事を参照して入れてください