適当おじさんの適当ブログ

技術のことやゲーム開発のことやゲームのことなど自由に雑多に書き連ねます

いまさらながら Flask についてまとめる 〜Configuration〜

はじめに

いまさらながら Flask について整理していきます。「Flaskとかいうやつを使って、試しにアプリ開発にトライしてみたい」くらいの感覚の人を対象にしています。

Flaskのバージョンは 0.12.2 です。

この記事では、Flaskアプリケーションの設定方法や切り替え方について紹介します。その他のFlaskまとめシリーズはこちらから

アプリケーションの設定について

なんらかのアプリケーションを動作させるとき、その環境によって設定を変更したい場合があります。

たとえば、DBの接続情報です。一般的に、開発環境と本番環境で異なるDBに接続します。そうでなければ本番環境のDBにゴミデータを混ぜ込んでしまったり、データを破壊してしまう恐れがあるためです。また、デバッグモードは開発環境ではONにしますが、本番環境では一般的にOFFにします。

小さなアプリケーションであれば、ささっと設定内容をハードコーディングしてしまうのも悪くないかもしれません。しかし、Flaskではハードコーディングする以外の手段も提供しています。

Flaskの設定はどこに保存されるのか

Flaskクラスの config 属性に格納されています。config はdictionaryを継承した Configクラスのインスタンスです。

from flask import Flask

app = Flask('sample')
print(app.config)

上記コードを実行すれば、configの値、つまり、アプリケーションの設定内容を確認できます。すべての設定項目は、 公式のリファレンス をご確認ください。

設定をハードコーディングする場合は、configに値を設定してやれば良いです。以下は、DEBUGモードをONにする場合の例です。

app = Flask('sample')
app.config['DEBUG'] = True

configはdictionaryを継承しているので、設定にあたってdictionaryの各種メソッドを使うこともできます。短期的に見るとこの方法がもっとも簡単なのですが、設定項目等が増えてくると長々と設定を記載する羽目になります。これはあまり綺麗な書き方とは言えません。

Flaskの提供する設定方法

Configクラスが持つ値更新用のメソッドを利用します。

方法 メソッド名
名前=値形式で記載された設定ファイルから読み込む from_pyfile
環境変数に指定されている設定ファイルから読み込む from_envvar
専用クラスで定義した値を読み込む from_object
json形式の設定ファイルを読み込む from_json
辞書型のデータを読み込む from_mapping

なお、設定値のキーはすべて大文字にしなければなりません。設定値に小文字を含んでいてもエラーにはなりませんが、すべて無視されます。

configはdictionaryを拡張したものなので、独自の設定値を追加することもできます。守らなければいけないルールは、キーを大文字にするということだけです。

具体例

開発、テスト、本番の3つの環境があるという前提で話を進めます。

from_pyfile

設定ファイルのパスを指定して、読み込みます。

app.config.from_pyfile('development.cfg')
# development.cfg
DEBUG=True
TESTING=False

from_pyfile に文字列でファイルパスを設定してしまうと、環境ごとに柔軟に設定ファイルを切り替えるのが難しくなります。そのため、環境変数を使って設定を切り替えることが多いです。

from_envvar

from_envvarは、環境変数に設定されたファイルパスを元に設定を読み込みます。

$ export FLASK_CONFIG_FILE_PATH=/path/to/development.cfg
app.config.from_envvar('FLASK_CONFIG_FILE_PATH')

この方法であれば、環境変数を設定するだけで読み込む設定ファイルを切り替えることができます。ちなみに、from_envvar は内部で読み込んだ環境変数の値をもとに from_pyfile を実行しています。

from_json

こちらはjson形式の設定ファイルを読み込みます。from_envvarに該当するものはバージョン0.12の時点ではありません。

app.config.from_json('app_config.json')
{                                                                               
    "DEBUG": true,                                                              
    "TESTING": false                                                                                                                                
} 

ここまで紹介した3つの設定読み込み関数の第2引数には silent というものがあります。デフォルトでは False であり、True にすると、ファイルや環境変数が見つからなかった場合に例外を発生させるのではなく、False を返すようになります。

# return False
app.config.from_json('not_exist_config.json', True)

from_object

これまでのファイルから設定値を読み込むのとは異なり、専用クラスで定義した値を読み込みます。以下の例では、本番環境用の設定ファイルを読み込んでいます

app.config.from_object("config.ProductionConfig")
# config.py
class Development(object):
    DEBUG = True
    DB_URI = "開発環境の設定"

class Testing(object):
    TESTING = True
    DB_URI = "テスト環境の設定"

class Production(object):
    DB_URI = "本番環境の設定"

instanceフォルダ

設定値に、APIキーなど機密性の高い設定情報を含みたい場合があります。しかし、機密性の高い情報を設定ファイルに直接書くわけにはいきません。うっかり機密性の高い情報を含んだ設定ファイルをGithubにプッシュしてしまったら、全世界に機密情報をばらまくことになってしまいます。Flaskではinstanceフォルダを、そうした機密情報置き場としています。

app_dir/
    app.py
    sample_app/
        __init__.py
        views.py
    instance/
        config.cfg

ただし、instanceをバージョン管理しない設定(.gitignoreへの追加)は自分でしておかなければなりません。 そういったしきたりで扱うというだけで、Flaskが勝手にバージョン管理外のファイルとして扱ってくれるということではありません。

デフォルトのinstanceフォルダは instance/ です。instanceフォルダのパスは自由に設定できます。なお、絶対パスでしか指定できません。

app = Flask(__name__, instance_path='/home/app_dir/custom_instance')
print(app.instance_path) # instanceフォルダのパスを出力

app.config.from_pyfile('custom_instance/config.cfg')

instanceフォルダ以下のファイルを読み込む場合は、この記事で紹介した各種メソッドで読み込むことができます。ファイルパスを指定する際に、instanceフォルダを毎回指定するのは手間がかかります。アプリケーションのrootパスではなく、自動的にinstanceフォルダを見るように設定を切り替えることができます。

app = Flask(__name__, instance_relative_config=True)

# instance/config.cfg と指定しなくてよい
app.config.from_pyfile('config.cfg')

どう使うのが良いのか

まとめると、以下のような方針で設定ファイルを作成するのが良いように思えます。

  • 柔軟に設定を切り替えられるように、環境変数を用いる
  • 開発環境、テスト環境、本番環境ごとに設定を作る
  • 機密性の高い情報は、instance以下に設定ファイルを作成する
app_dir/
    app.py
    config.py
    sample_app/
        __init__.py
    instance/
        sensitive_data.cfg
# app.py
import os

from flask import Flask

config_type = {
    "development":  "config.Development",
    "testing": "config.Testing",
    "production": "config.Production"
}

app = Flask('sample', instance_relative_config=True)
app.config.from_object(config_type.get(os.getenv('FLASK_APP_ENV', 'production')))
app.config.from_pyfile('sensitive_data.cfg')

設定ファイルは、from_objectの説明のところに書いてあるものをそのまま使っています。また、instanceフォルダに切り替えているので、 from_pyfile がinstance以下を見るようになっています。なので、機密性の高い情報以外の設定は、from_object で読み込むようにしています。

また、環境変数がない場合はデフォルトで production の設定が反映されるようにしています。Flaskはオプションを設定せずに起動した場合に非デバッグモードで起動します。その挙動と合わせて、デフォルトはproductionとしています。また、環境変数を設定し忘れて、うっかりデバッグモードで実行してしまうことを防げます。