Avatar ·

Как сделать несколько конфигураций (settings.py) для проекта Django?

📁 пример, django, debug, проект

Довольно очевидно, что, например, на продакшене и при разработке конфигурация проекта должна быть разная. Однако по умолчанию Django предусматривает использование одного-единственного settings.py, в котором лежит всё подряд, без каких-либо намёков на разделение. А разделить хочется.

Например, при разработке можно включить DEBUG = True и подключить Debug Toolbar, чего на продакшене делать нельзя, использовать какую-то конкретную локальную базу данных разработчика, смягчить ограничения и т.д.

Кроме того, если захочется опубликовать Django-проект на каком-нибудь гитхабе, то добавлять в репозиторий settings.py со всеми паролями совсем не круто. А если удалять оттуда пароли, коммитить и возвращать пароли обратно, то это всё совершенно неудобно, и можно случайно забыть это и закоммитить settings.py с паролями. Да и конфликты будут.

Как можно разделить конфигурацию на разные части, чтобы параметры продакшена, параметры разработки и пароли лежали как-то отдельно друг от друга?

Avatar ·

В интернете водится несколько всяких разных способов разделения конфигурации Django, но самым лучшим мне кажется разделение через модули и DJANGO_SETTINGS_MODULE.

Запуск Django начинается с чтения Python-модуля с настройками, и имя нужного модуля должен быть указан в переменной окружения DJANGO_SETTINGS_MODULE — без него Django просто не запустится. Чтобы разработчику было проще жить, команда django-admin startproject автоматически прописывает DJANGO_SETTINGS_MODULE со значением вида yourproject.settings в файлы manage.py, wsgi.py и asgi.py. Таким образом, меняя значение DJANGO_SETTINGS_MODULE, мы можем переключаться между разными файлами настроек.

Чтобы разделить продакшен и разработку, я предлагаю вместо файла settings.py использовать каталог settings с подмодулями внутри. Структура примерно такая:

├─ yourproject/│  ├─ settings/│  │  ├─ __init__.py│  │  ├─ base.py│  │  ├─ development.py│  │  └─ production.py│  ├─ __init__.py│  └─ asgi.py│  ├─ models.py│  ├─ urls.py│  └─ wsgi.py├─ local_settings.py└─ manage.py

В файле base.py хранятся настройки по умолчанию, общие для всех окружений. В файлах development.py и production.py хранятся отдельные настройки для разработки и продакшена соответственно. Файла settings.py нет вообще.

Содержимое файла base.py аналогично обычному settings.py — можно его просто переименовать.

В файле development.py прописываем штуки, упрощающие разработку и отладку:

from .base import *  # подгружаем настройки по умолчаниюDEBUG = TrueALLOWED_HOSTS = ['*']INSTALLED_APPS = INSTALLED_APPS + ['debug_toolbar']MIDDLEWARE = ['debug_toolbar.middleware.DebugToolbarMiddleware'] + MIDDLEWARE# и так далее

В файле production.py прописываем настройки, специфичные для «боевого» окружения:

from .base import *DEBUG = FalseALLOWED_HOSTS = ['yourproject.example.com']

Пароли и секретные ключи здесь не хранятся! Точнее, вы можете прописать в base.py базу данных sqlite и какие-нибудь стандартные ключи, но считать их секретными не стоит: идея в том, что все эти файлы могут быть безопасно опубликованы без каких-либо изменений.

Как теперь выбрать нужную конфигурацию? Для начала вспомним, что она уже прописана в файле manage.py путём установки значения по умолчанию. Теперь нужно его заменить примерно так:

# manage.py# ... найдите такую строку в файле и обновите её:os.environ.setdefault(""DJANGO_SETTINGS_MODULE"", ""yourproject.settings.development"")

Когда вы хотите выбрать какую-то другую конфигурацию, вам следует заменить переменную окружения DJANGO_SETTINGS_MODULE. Все варианты её замены в разных ОС расписывать не буду, но вот пример (*nix, sh):

DJANGO_SETTINGS_MODULE=yourproject.settings.development ./manage.py runserver

Подключения к базам данных, пароли и секретные ключи следует хранить в файле local_settings.py. Этот файл секретен, не должен быть добавлен в репозиторий (для git его нужно прописать в .gitignore) и не должен нигде публиковаться. Он может выглядеть примерно так:

# Этим импортом вы можете выбирать между development и productionfrom yourproject.settings.development import *DATABASES = { ... чтототам ... }SECRET_KEY = '230eoqd439wej9c0eru384jfsc'EMAIL_HOST_PASSWORD = '123456'# и все остальные секретики

Подключить его можно через ту же самую DJANGO_SETTINGS_MODULE:

DJANGO_SETTINGS_MODULE=local_settings ./manage.py runserver

Однако постоянное прописывание переменной окружения кажется неудобным. Можно прописать local_settings точно так же внутри файла manage.py и жить спокойно. Однако, возможно, вы захотите, чтобы файл local_settings.py был необязателен для работы проекта (как этого захотел я), поэтому можно прописать выбор конфигурации в зависимости от того, существует файл или нет:

# manage.py# ...if os.path.isfile(os.path.join(os.path.diame(__file__), 'local_settings.py')):    # Если рядом с manage.py лежит local_settings.py — используем его    os.environ.setdefault(""DJANGO_SETTINGS_MODULE"", ""local_settings"")else:    # Если нет — используем стандартные настройки без секретов    os.environ.setdefault(""DJANGO_SETTINGS_MODULE"", ""yourproject.settings.development"")

Кроме того, стоит помнить, что DJANGO_SETTINGS_MODULE также обычно прописан в файле wsgi.py (а с версии 3.0 добавился asgi.py), и когда вы будете (uwsgi, gunico, uvico и пр.), то стоит провести аналогичные изменения и в этих файлах.

(Впрочем, на мой субъективный взгляд, может оказаться лучше вообще удалить упоминания DJANGO_SETTINGS_MODULE из wsgi.py и asgi.py и всегда задавать переменную окружения извне — это повысит контроль над проектом и предотвратит случайный запуск с неправильными настройками.)

Войдите чтобы оставить ответ

Блоги