Django python-decoupleを使って設定を分離する方法

セキュリティ上の理由でコードに直接書いていけない設定を規定しているケースがあります。例えばDjangoの場合SECRET_KEYやDB設定が該当しやすいです。

python-decoupleはコードから設定を簡単に分離する事が可能なモジュールです。環境毎に設定を変えたい時にも役立ちます。

今回はpython-decoupleについて解説します。解説はpython-decoupleのGitHubリポジトリのREADMEを参考にしています。

python-decoupleとは?

python-decouple(以下decouple)は設定をコードから分離するためモジュールです。主な特徴は次のとおりです。

  • アプリを再デプロイせずにパラメーターを変更できる
  • パラメータをsettings.iniファイルや.envファイルで管理できる
  • デフォルト値を定義できる
  • 値のデータ型を指定できる

インストール方法・使用方法

インストール方法

pip install python-decouple

settings.pyの編集

configをインポートするコードを追記します。

from decouple import config

コードから分離したい設定をconfigを使って書き直します。default引数でデフォルト値を設定したり、cast引数でデータ型を指定する事ができます。

SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
EMAIL_HOST = config('EMAIL_HOST', default='localhost')
EMAIL_PORT = config('EMAIL_PORT', default=25, cast=int)

設定ファイル

decoupleはsettings.iniファイルや.envファイルを読み込みます。これらのファイルはsettings.pyと同じディレクトリに作成すれば問題ないです。

環境変数から読み込むことも可能なので作成は任意です。

decoupleが設定ファイルを探索する方法は、最初にconfigをインポートしたファイルと同じディレクトリを検索しなければ親ディレクトリを検索します。それでも見つからない場合は更に親ディレクトリを検索します。設定ファイルが見つかるまでこれを繰り返し、ルートまで探索したら終了します。

.envファイル

.envファイルは以下の様に書きます。

DEBUG=True
TEMPLATE_DEBUG=True
SECRET_KEY=ARANDOMSECRETKEY
DATABASE_URL=mysql://myuser:mypassword@myhost/mydatabase
PERCENTILE=90%
# コメント

settings.iniファイル

settings.iniファイルは以下の様に書きます。

[settings]
DEBUG=True
TEMPLATE_DEBUG=%(DEBUG)s
SECRET_KEY=ARANDOMSECRETKEY
DATABASE_URL=mysql://myuser:mypassword@myhost/mydatabase
PERCENTILE=90%%
# コメント

注意)PERCENTILEの様に%文字を使いたい場合は%%と連ねて書く必要があります。

読み込み順序

Decoupleは次の順序で設定を検索します。

  1. 環境変数
  2. 設定ファイル
  3. configに渡されるデフォルト値

1の環境変数で設定を定義する場合は2の設定ファイルは必須ではありません。

1と2を使い分けることも可能です。例えば複数人で開発をする場合は、開発時は各々が.envファイルで設定値を自由に定義して、ステージング環境やプロダクション環境では環境変数を使うといった具合です。

Djangoでの使い方

例1)コードに設定値を書きたくない場合は次の様にデフォルト値を指定しません。

SECRET_KEY = config('SECRET_KEY')

環境変数や設定ファイルにSECRET_KEYが定義されていない場合、UndefinedValueError例外が発生します。この方法によりパラメータの設定漏れを回避する事ができます。

例2)dj_database_urlモジュールを使うとデータベースURLをcastする時に役立ちます。

from decouple import config
from unipath import Path
from dj_database_url import parse as db_url

BASE_DIR = Path(__file__).parent

DATABASES = {
    'default': config(
        'DATABASE_URL',
        default='sqlite:///' + BASE_DIR.child('db.sqlite3'),
        cast=db_url
    )
}

cast引数の使い方

.envファイルが次の様に書かれているとします。

DEBUG=True
EMAIL_PORT=42
ALLOWED_HOSTS=.localhost, .herokuapp.com
SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO, https

これらの設定をconfigを使って読み込んだ時、得られる結果はコメント文の値になります。

config('DEBUG', cast=bool) # False
config('EMAIL_PORT', cast=int) # 42
config('ALLOWED_HOSTS', cast=lambda v: [s.strip() for s in v.split(',')]) # ['.localhost', '.herokuapp.com']
config('SECURE_PROXY_SSL_HEADER', cast=Csv(post_process=tuple)) # ('HTTP_X_FORWARDED_PROTO', 'https')

boolやint以外にも関数やtupleも指定できます。ALLOWED_HOSTSの値は関数を使ってリスト型に変換していますが、decoupleに組み込まれているCsvクラスを使うとより簡単に書けます。

組み込みのCsvクラス

上記のALLOWED_HOSTSをCsvを使って書くと以下の様になります。

from decouple import Csv
config('ALLOWED_HOSTS', cast=Csv()) # ['.localhost', '.herokuapp.com']

デフォルト値を指定したい場合はlistではなくstringにして下さい。

from decouple import Csv
config('ALLOWED_HOSTS', default='127.0.0.1', cast=Csv()) # ['127.0.0.1']

他のデータ型のリストを取得することもできます。以下ではint型のリストを取得しています。(pythonのインタープリターで実行した例です)

>>> os.environ['LIST_OF_INTEGERS'] = '1,2,3,4,5'
>>> config('LIST_OF_INTEGERS', cast=Csv(int))
[1, 2, 3, 4, 5]

組み込みのChoices

Choicesクラスを使うと選択肢を設定できます。選択肢以外の値が定義されていた場合ValueError例外が発生します。

>>> from decouple import config, Choices
>>> os.environ['CONNECTION_TYPE'] = 'usb'
>>> config('CONNECTION_TYPE', cast=Choices(['eth', 'usb', 'bluetooth']))
'usb'

Choicesクラスを使うときも型を指定する事が可能です。

>>> os.environ['SOME_NUMBER'] = '42'
>>> config('SOME_NUMBER', cast=Choices([7, 14, 42], cast=int))
42

上記の方法でcast引数の使い方をほぼカバーしていますが、より詳しく知りたい場合は公式サイトをご参照下さい。

まとめ

decoupleで設定をコードから簡単に分離できます。デフォルト値やcastする方法もわかりやすいです。

複数人で開発する場合はsettings.pyをconfigを使って書き換えて、開発者各々が設定ファイルを作成すれば開発しやすいでしょう。

スポンサーリンク
スポンサーリンク