nikkie-ftnextの日記

イベントレポートや読書メモを発信

Djangoの設定ファイルの分割について知りたく、書籍・記事を調査しました

この記事は、Django Advent Calendar 2022 11日目の記事にしちゃいます(1/1に書いたので)。
Djangoに興味があるそこのあなた! よろしければ時を戻した投稿をしてみませんか?🎸

はじめに

歩夢だぴょん! あゆぴょんだぴょん!1
明けましておめでとうございます!
卯年ですね、nikkieです。

Python製Webアプリケーションフレームワークの1つ、Django(ジャンゴ)。
Djangoには設定ファイルがあり、これを分割できます。
「この分割は具体的にどうやるのか」を知りたく、文献調査しました。
分かったことをまとめます。

目次(=あたった文献リスト)

前提

Djangoの設定ファイルとは

Django Girls Tutorialでは「プロジェクトを作成しよう!」の「設定変更」に設定ファイルについて記載があります。
django-admin startproject プロジェクト名 .2すると、プロジェクト3が作られ、<プロジェクト名>/settings.pyも配置されます(詳しくはチュートリアルをどうぞ)。
このsettings.pyがこの記事で言う「設定ファイル」です4
これの分割を考えていきます。

設定ファイルのドキュメントは以下です。

Djangoの設定 | Django ドキュメント | Django

この記事の前提

  • 執筆者はDjangoを実務で使っていません。趣味開発5です
  • 趣味開発のDjangoアプリの設定ファイルの分割についてハマってなんとか対処しました
    • この経験で「設定ファイルの分割って分かってないな」と感じたので、自分の理解を深めるためにいくつかの文献にあたることにしました
  • 深まった理解(次の趣味開発で採用する暫定的な結論)を元にアウトプットします
    • もっといい方法をご存じの方はぜひ教えてください
  • Djangoのバージョンは執筆時点で最新の4.1としてドキュメントを見ていきます
    • 4.1はLTSではないので、今後リンク先のドキュメントが古くなっていくと思います。その場合はサポート中のバージョンで確認してください(LTSの4.2など)

暫定的な結論

  • 次に作るDjangoアプリでは(startprojectせずに)cookiecutter-djangoを使う
    • django-environを使って共通設定ファイル+環境変数の形(The Twelve-Factor App準拠)にまとめつつ、環境変数で設定しきれない部分は設定ファイルを環境ごとに分けて対応
  • すでに作ったDjangoアプリも設定ファイルを分割しているなら、cookiecutter-djangoに近づけたい

この結論に至った過程は以下をどうぞ!

初手『実践Django

「9.9 設定ファイルの分割」というズバリなトピックがありました。
2つのやり方が紹介されています。

  1. プロジェクトのディレクトリの中に環境ごとの設定ファイルを置く(複数の設定ファイルが置かれる)
  2. 設定ファイルの数を増やす代わりに、1つの設定ファイルで設定を環境変数で切り替える

The Twelve-Factor App III. 設定

2についてはThe Twelve-Factor App6で推奨される方法として紹介されます。

Twelve-Factorは 設定をコードから厳密に分離すること を要求する。

なお、この“設定”の定義には、アプリケーション内部の設定は 含まない ことに注意する。

Twelve-Factor Appは設定を 環境変数 に格納する。

概要はつかめました。
具体的にどうやるのかを見ていきます。

過去に見た資料 「本番運用を想定したDjango settings.pyの書き方入門」

Python実践レシピ』の著者の1人、筒井さんによる2021年のアウトプットです。

この資料を見たときの私のブックマークがこちら7

1.settings. pyを環境ごとに分ける(baseをimportして環境ごとに設定)2.秘密の値の環境変数からの読み取り、ImproperlyConfiguredを送出。3.ログ出力は標準出力のみ。cookiecutter-djangoで3つとも試せる。two scoop本3.0出た!

ブックマークコメントのうち、今回の調査トピックに関わってくるのは1と2ですね。

1について、settings.pyをsettings/base.pyとし、settingsディレクトリ下に環境ごとの設定ファイルを置きます。
settingsパッケージ導入というわけですね。

環境ごとの設定ファイルではfrom base import *として共通の設定を読み込むのがポイント!(slide=18)

2について

  • 秘密の値は環境変数から読み取る(slide=26)
  • os.environをラップし、必須の環境変数が設定されていなければImproperlyConfiguredを送出する関数で読み取る(slide=27 コードあります)
  • サードパーティライブラリdjango-environに言及(slide=28。この記事でも後述

2の関数の実装については『Two Scoops of Django 3.x』が参照されています。

筒井さんの発表は記事版の寄稿もあります(2022年11月)。

脱線:分割した設定ファイルはどう指定する?

筒井さんのスライドにもありますが(slide=19)、複数の設定ファイルから1つを指定するやり方は2つあります。

  1. 環境変数DJANGO_SETTINGS_MODULE8
  2. django-admin--settingsオプション9

django-admin と manage.py | Django ドキュメント | Django

もし複数の Django 設定ファイル間での切り替えが必要な場合は、django-admin を DJANGO_SETTINGS_MODULE もしくは --settings オプションと共に利用してください。

Djangoの設定 | Django ドキュメント | Django

django-admin を使う場合、環境変数を予め指定しておくか、ユーティリティを起動する度に設定モジュールを明示的に渡します。

また、筒井さんのスライド(slide=22)では、manage.pyデフォルトの設定をしている箇所を変更して、設定ファイル1つを指定しています。

ここで紹介した箇所には、環境ごとの設定ファイルが指定されます。
共通の設定であるsettings/base.pyは指定されません。

『Two Scoops of Django 3.x』 「5 Settings and Requirements Files」

筒井さんが参照していた 『Two Scoops of Django 3.x』も確認します。

「5 Settings and Requirements Files」での主張は以下かなと思います:

  • 設定ファイル(秘密情報を除く)とrequirementsファイルはバージョン管理しよう
    • 環境ごとに設定ファイルとrequirementsファイルを分割する方針
  • 分割するが、DRYにする(繰り返さない)
    • 筒井さんのスライドにあった共通の設定からのアスタリスクimport
    • requirementsファイルでも適用できる(共通のrequirementsを作る)
  • 秘密情報(SECRET_KEY10の設定値や、各種APIのキー)はバージョン管理しない
    • 環境変数
    • 秘密情報をまとめたファイルから読み取る

1点目「バージョン管理しよう」から、「各自の開発環境にバージョン管理しないlocal_settings.pyを作る方法」はアンチパターンと紹介されます。
書きぶりからの推測ですが、過去にlocal_settings.pyを推していたが、少なくとも3.x版からは非推奨のようです。

3点目「秘密情報」の「環境変数」からの読み取りでは、筒井さんのスライドと同様の範囲がカバーされていました。

Two Scoops本が参照していた「The Best (and Worst) of Django」(2011)

The setup described here is based on the so-called “The One True Way”, from Jacob Kaplan-Moss’ The Best (and Worst) of Django talk at OSCON 2011. (p.45 5.2)

「The Best (and Worst) of Django」のスライド自体は Do the simplest thing that could possibly work. (Simon Willison) を繰り返し引用し、simpleなやり方を提案しています。
その中でlocal_settings.pyアンチパターンと述べられています(slide=47)。
提案されるのが、上記のように、環境ごとに分割した設定ファイルを置く方法(The One True Way)です。

slide=47を見て、「バージョン管理しないlocal_settings.pyを置く方法」がどういう方法か分かりました。
local_settings.pyがあればアスタリスクimportして、設定値を上書きするんですね。

try:
    from local_settings import *
except ImportError:
    pass

django-environ

いくつかの文献で存在が紹介されているライブラリdjango-environを見てみましょう。

django-environ is the Python package that allows you to use Twelve-factor methodology to configure your Django application with environment variables.

(意訳) django-environは、Djangoアプリケーションを環境変数で設定できるようにすることで、あなたがTwelve-factor方法論を使えるようにするPythonパッケージです。

上記リンク先のOverviewから引用します:

Using django-environ you can stop to make a lot of unversioned settings_*.py to configure your app.

(意訳) django-environを使うことで、アプリを設定するためにバージョン管理されていないたくさんのsettings_*.pyを作るのを止められます。

Quick Startに使い出しに必要な情報がまとまっています。

settings.pyは1つで、環境変数.envファイルに定義)を複数作って切り替えるのがイメージできます。

小まとめ:環境ごとの設定を実現する2つの方法

ここまでの私の理解ですが、

  • 設定ファイルはバージョン管理する(『Two Scoops of Django 3.x』)
    • バージョン管理せず、環境ごとに設定ファイルを用意するのは非推奨(django-environ
      • 『実践Django』で紹介された環境ごとに設定ファイルを用意するのも、バージョン管理前提と理解
    • バージョン管理しないlocal_settings.pyは非推奨(『Two Scoops of Django 3.x』)
  • 方法1:設定ファイルの分割(「The Best (and Worst) of Django」)
    • 環境ごとに設定ファイルができるが、DRYにしてファイルの多さに対処しているという理解
  • 方法2:1つの設定ファイル + 環境変数で切り替え
    • The Twelve-Factor Appで推奨される方法
    • django-environが可能にする
    • (完全に1つのファイルにはできないのではないか。後述)

cookiecutter-django

django-environのOverviewには次のようにあります。

See cookiecutter-django for a concrete example on using with a django project.

(意訳) Djangoプロジェクトで使う具体的な例については、cookiecutter-djangoを見てください

というわけで見に行ってみましょう!

Cookiecutterとは、プロジェクトテンプレートからプロジェクトを作れるツールです(Python実装)。
Django用のテンプレートがcookiecutter-djangoというわけですね。

Powered by Cookiecutter, Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly.

(意訳) Cookiecutter Djangoは、Cookiecutterを活かして、本番環境で動作できるブーストしたDjangoプロジェクトを素早く用意するためのフレームワークです。

今回は設定ファイルまわりに絞って見ます。
テンプレートの中の設定ファイルは以下にありました。

https://github.com/cookiecutter/cookiecutter-django/tree/2022.12.29/%7B%7Bcookiecutter.project_slug%7D%7D/config/settings

ディレクトリ構成

settings/
├── __init__.py  # 空。settingsパッケージにするために必要
├── base.py  # 共通設定。環境ごとの設定でアスタリスクimportされる
├── local.py  # 開発環境用
├── production.py  # 本番環境用
└── test.py  # テスト用

settings/base.pyを見ると、たしかにdjango-environを使った例になっています。
環境ごとの設定ファイルではbase.pyからdjango-environのオブジェクト(env)をimportして設定の上書きをするなど、参考になるところは多いですね。

環境変数を使って設定をbase.pyに寄せつつも、1つの設定ファイルとなっていない理由の1つはINSTALLED_APPSではないかと思います。
例えばDjango Debug Toolbarは開発環境でだけ使いたいですよね。
INSTALLED_APPSの設定は環境変数に寄せきれないから、大きな共通設定base.pyと、環境ごとの差分の設定というふうに分かれているのかなと思います。
小まとめの2つの方法のうち、なるべく方法2(1つの設定ファイル+環境変数)をやりつつ、できない部分は方法1(設定ファイルの分割)とするというハイブリッドな形なのかなと理解しました。

終わりに

Djangoの設定ファイルの分割、具体的にどうやるのか」という疑問から文献調査をしました。

cookiecutter-django、いいですね(django-environの思想、素晴らしい)。
Django Girls Tutorialで入門した頃は今ひとつよさが分かりませんでしたが、趣味開発でいくつかアプリを作り経験値が貯まったことで、設定ファイルの分割含めテンプレートのよさを認識できた感じです。
Djangoアプリのベストプラクティスを表しているとも思うので、素振りとして、cookiecutter-djangoのテンプレートに採用されているまだ見ぬパッケージを触りに行くとDjango力が付きそうな印象です。

P.S. その1 akiyokoさんの『現場で使える Django の教科書《基礎編》』では

2018年の技術書典4版を参照しているので、最新版ではアップデートされている可能性が高いです11

  • local_settings.py
    • 『Two Scoops of Django 3.x』では非推奨とされた方法
  • django-environを紹介

P.S. その2 設定ファイルの差分が見られる! diffsettings

https://docs.djangoproject.com/ja/4.1/ref/django-admin/#diffsettings

django-admin diffsettingsコマンドは

  • 現在の設定ファイルと、Djangoのデフォルト設定
  • 現在の設定ファイルと、指定した設定ファイル

の差分を表示するそうです。

複数の設定ファイルがあるときに気になるであろう差分も、簡単に確認できそうですね。
『Two Scoops of Django 3.x』5.6で存在を知りました。


  1. https://docs.djangoproject.com/ja/4.1/ref/django-admin/#startproject
  2. Djangoの用語として、プロジェクトは「Webアプリケーション全体の構成」を表します。実体はいくつかのファイルです(__init__.pyが置かれるのでPythonパッケージになっています) ref: https://github.com/ftnext/2020_slides/blob/master/pycon_shizu_Feb_django_intro/parts/2-django_girls_tutorial/2-1_request_response.md
  3. settings.pyモジュールでもあるため、「設定モジュール」とも呼ばれていました。 ref: 「モジュールは Python の定義や文が入ったファイルです。ファイル名はモジュール名に接尾語 .py がついたものになります。6. モジュール — Python 3.11.0b5 ドキュメント
  4. レベル感のご参考まで 自作Djangoミニアプリ、テンプレートで頑張っていた検索フォームの実装をDjangoフォームで書き直しました - nikkie-ftnextの日記
  5. Twelve-Factor Appは方法論とのことです。「Twelve-Factor Appは、次のようなSoftware as a Serviceを作り上げるための方法論である。
  6. この資料は2021年5月と10月の2つのバージョンがあります。ブックマークは1つ前のバージョンに対してですが、資料を見た限り内容的な差分はほとんどなさそうでした
  7. https://docs.djangoproject.com/ja/4.1/topics/settings/#envvar-DJANGO_SETTINGS_MODULE
  8. https://docs.djangoproject.com/ja/4.1/ref/django-admin/#cmdoption-settings
  9. Djangoの設定ファイルの中のSECRET_KEY暗号署名に使われます。詳しくは 暗号署名 | Django ドキュメント | Django をどうぞ
  10. 「設定ファイルについて大幅加筆(第10章)」 ref: これぞベスト・オブ・Django 本!『現場で使える Django の教科書《基礎編》』が Kindle で販売中 - akiyoko blog