今回の内容
前回はDjangoの実践的なテストの書き方と、CircleCIを使った継続的インテグレーションについて解説しました。前回までのコードは以下から取得できます。
第4回となる今回は、まず環境変数について取り上げます。環境変数を用いたsettingsファイルの書き方を紹介した後は、Angularを使ってカンバンボードのUIを実装していきます。
環境変数
環境毎に異なる値としては、データベースの接続に必要な情報やTwitterなど外部サービスの認証情報等が思い浮かぶと思います。これらの設定を定数としてコード上で管理することはもちろん可能ですが、セキュリティと保守性の観点から推奨されません。「The Twelve-Factor App」の教えにのっとり、設定は環境変数から渡すようにしましょう。
「The Twelve-Factor App」とは、Heroku創業メンバーの一人が書いた、WebアプリケーションやSaaSを作り上げるための方法論です。日本語訳もあるので、ご存じない方はぜひ一度目を通してみてください。
Django-environ
Djangoで環境変数を扱うには、Django-environというサードパーティ製パッケージが便利です。Django-environは、.envファイルのサポートや簡潔なファイルパス指定といったメリットがあり、cookiecutter-djangoでも使われています。
それでは、Django-environをインストールします。
(env) $ pip install django-environ (env) $ vi requirements/base.txt (env) $ cat requirements/base.txt Django==2.0.2 django-environ==0.4.5 django-model-utils==3.1.1 djangorestframework==3.7.7
インストールが無事済んだら、config/settings/base.pyの先頭に以下のコードを追加しましょう。
import environ
ROOT_DIR = environ.Path(__file__) - 3 # (modern-django/config/settings/base.py - 3 = modern-django/)
env = environ.Env()
READ_DOT_ENV_FILE = env.bool('DJANGO_READ_DOT_ENV_FILE', default=False)
if READ_DOT_ENV_FILE:
# OS environment variables take precedence over variables from .env
env.read_env(str(ROOT_DIR.path('.env')))
ここで記述したif文は、「環境変数でDJANGO_READ_ENV_FILEをTrueに設定している場合のみ、.envファイルの値を読み込む」ということを意味しています。このおかげで開発環境での環境変数の管理が楽にできます。
また、environ.Path(__file__) - 3のようにファイルパスの扱いが直感的にできるようになっているのもDjango-environの特徴のひとつです。
それでは次に、DEBUGとSECRET_KEYをそれぞれ環境変数から読み込むように修正してみましょう。現在のコードでは、SECRET_KEYにはプロジェクト作成時にそれぞれ異なるランダムな文字列が、DEBUGにはTrueが設定されています。それをDjango-environを利用して、以下のように書き直します。
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env.bool('DEBUG', False)
DEBUG = env.bool('DEBUG', False)は、変数DEBUGがbool型であり、環境変数DEBUGが設定されていない場合にはFalseがデフォルト値として使われるということを意味しています。env.bool()がTrueとして評価する環境変数の値は以下の6パターンです(大文字と小文字は区別されません)。
- 'true'
- 'on'
- 'ok'
- 'y'
- 'yes'
- '1'
.envファイルも用意しておきましょう。リポジトリ直下に.envファイルを作成します。
(env) $ vi .env (env) $ cat .env DEBUG=True SECRET_KEY=<config/settings/base.pyに記述されていたランダムな文字列>
.envファイルには認証情報などを記載する場合もあるので、リポジトリにpushしないために.gitignoreに.envを追加してください。
また.envファイルのひな型として、.env.exampleファイルを用意しておくことをお勧めします。.env.exampleファイルを用意することにより、.envファイルにどういった値を設定すればよいかわかりやすくなるだけでなく、.gitignoreに追加されている.envファイルの存在を見落とさなくなるメリットがあります。
(env) $ vi .env.example (env) $ cat .env.example DEBUG=True SECRET_KEY=your-secret-key
この状態で開発サーバーを起動すると、環境変数にSECRET_KEYが見当たらないというエラー(KeyError)が発生します。
(env) $ python manage.py runserver
Traceback (most recent call last):
File "/Users/massa142/src/github.com/massa142/modern-django/env/lib/python3.6/site-packages/environ/environ.py", line 273, in get_value
value = self.ENVIRON[var]
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/os.py", line 669, in __getitem__
raise KeyError(key) from None
KeyError: 'SECRET_KEY'
手元の環境で動かすためには、最後に環境変数DJANGO_READ_DOT_ENV_FILEに値Trueをセットしましょう。これで先ほど用意した.envファイルの値が環境変数として読み込まれます。
(env) $ export DJANGO_READ_DOT_ENV_FILE=True (env) $ python manage.py runserver Performing system checks... System check identified no issues (0 silenced). January 08, 2019 - 08:39:30 Django version 2.0.2, using settings 'config.settings.local' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
継続的な開発をしていく際には、以下のように各自お使いのシェルにあわせて環境変数を設定しておくのがよいでしょう。
$ echo export DJANGO_READ_DOT_ENV_FILE=True >> ~/.bash_profile $ source ~/.bash_profile
Django-environにはまだ便利な機能が備わっています。例えば、適切に環境変数を登録しておくとenv.db()でデータベースの設定を済ませることができます。Django-environについて他にも詳しく知りたい方は公式ドキュメントを参照してください。
設定ファイルの切り替え
第3回では環境毎に設定ファイルの切り替えを行う方法として、manage.pyコマンドの--settingsオプションを紹介しました。CircleCIの設定に記述されているpython -Wd manage.py test --settings=config.settings.baseというコードがその一例です。
--settingsオプションについての詳細は前回の記事を確認してください。
--settingsオプションを都度指定するのが面倒だと感じたり、環境毎にsettingsファイルを分割して管理するのは煩雑だという場合は、1つのsettingsファイルで管理するアプローチを検討しましょう。
ここまで説明してきた環境変数とif文を用いることによって、settings.pyひとつで複数の環境に対応できます。
FeedHQというDjango製プロダクトのsettingsファイルの書き方が参考になるので、ぜひ確認してみてください。
