Короткий ответ
Общую конфигурацию выносят в базовый модуль settings/base.py, а окружение-специфичные настройки — в отдельные модули (settings/dev.py, settings/prod.py), которые импортируют base и переопределяют нужные значения; секреты передают через переменные окружения (например, с помощью django-environ), а не хардкодят.
Как это работает подробнее
DJANGO_SETTINGS_MODULE указывает, какой именно модуль настроек загружать при старте процесса (например, myproject.settings.prod); settings/prod.py обычно делает from .base import * и затем переопределяет DEBUG, ALLOWED_HOSTS, настройки БД, читая их значения из окружения.
Пример кода
example.py
# settings/base.py
INSTALLED_APPS = []
MIDDLEWARE = []
# settings/prod.py
import environ
from .base import *
env = environ.Env()
DEBUG = False
SECRET_KEY = env("SECRET_KEY") # обязательная переменная, упадёт при отсутствии
DATABASES = {"default": env.db("DATABASE_URL")}
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS")
# Запуск: DJANGO_SETTINGS_MODULE=myproject.settings.prod gunicorn myproject.wsgiЧто использовать на практике
- Практика. Такое разделение снижает риск случайно запустить production с
DEBUG=Trueили с SQLite вместо PostgreSQL.django-environ/python-decoupleупрощают чтение и приведение типов переменных окружения (env.bool('DEBUG', default=False)).
Подводные камни
- Риск. Используют один
settings.pyс большим количествомif os.environ.get('ENV') == 'prod':внутри, что усложняет чтение и тестирование конфигурации; забывают добавить обязательную проверку наличия критичных переменных окружения в production-модуле, из-за чего приложение стартует с «молчаливыми» дефолтами там, где это опасно (например,SECRET_KEYпо умолчанию).