86:状況依存の設定を環境変数に分離する

プログラミング迷子: 多段継承した設定ファイル

  • 後輩W:先輩、個人用の環境設定が必要になったら、設定ファイルを追加して from .local import * すれば良いですか?

  • 先輩T:どうして設定を追加したいの?

  • 後輩W:local.py で追加しているsilkを外すと少し動作が軽くなるので、自分の環境では解除しようかと思ってます。

  • 先輩T:もしかして、継承してINSTALLED_APPSから削除しようとしてる? 多段継承して差分実装を繰り返すのは良くないパターンだよ。別の方法を検討しよう。

85:設定ファイルを環境別に分割するsettings/ ディレクトリ配下の設定ファイルを base.pylocal.pystaging.py に分割しました。 local.py には DEBUG=True とsilkのインストールを指定するなど、各設定ファイルにはその環境で一番よく使う設定を実装しています。 しかし、そこからさらに継承した設定ファイルを用意するなど、設定ファイルを多段継承することには問題があります。

具体的な失敗

local_for_me.py のような個人用設定ファイルに from .local import * を書いてカスタマイズするのは簡単です。 このような設定ファイルを共有リポジトリにコミットすると、 settings/ 配下のファイルが増え、設定内容を把握するのが難しくなってしまいます。 また、同じ発想で検証環境用の設定ファイルを複数用意してしまうことには問題があります。 このような多段継承による差分実装を繰り返すと、当初はシンプルな方法でうまく対処したように見えても、徐々に設定の複雑化を招いてしまいます。

cover

(中略)詳細は書籍 自走プログラマー をご参照ください

ベストプラクティス

状況依存の設定値をコードから分離し、環境変数で設定しましょう。 DEBUG だけであれば以下のように実装できます。

リスト 4.4 settings.py
import os
DEBUG = bool(os.environ.get('DEBUG', False))

これで、環境変数 DEBUG がなければ DEBUG=False として動作します。 True にしたい場合は、 DEBUG=1 python manage.py runserver のように環境変数を指定して実行します。

環境変数をDjangoの設定に使う場合、 django-environ 1 パッケージを使うのが便利です。 Django以外でも同じように環境変数を設定に使いやすくするには python-decouple 2 が利用できます。 これらのツールは、環境変数を扱う便利な機能を提供しています。 また、OSの環境変数から値を読み取って利用できるだけでなく、 .env ファイルに書いた環境変数設定を読み込んで利用できます。 環境変数は、環境別のファイルで用意します。

リスト 4.5 .env.local
DEBUG=True
ALLOWED_HOSTS=127.0.0.1,localhost
INTERNAL_IPS=127.0.0.1
USE_SILK=True
DATABASE_URL=sqlite:///db.sqlite3
1

https://django-environ.readthedocs.io/

2

https://pypi.org/p/python-decouple/

cover

(中略)詳細は書籍 自走プログラマー をご参照ください