Pull to refresh

Собственный модуль settings

Reading time4 min
Views11K

Преамбула


Этот модуль родился в результате переосмысления (или недопонимания) мной вот этого пространного документа: Splitting up the settings file, размещённого на официальном сайте Django.

Постановка задачи


При старте веб-приложения на Django (как посредством запуска отладочного сервера, так и в качестве WSGI-приложения) фреймворк первым делом выполняет модуль, задающий начальные настройки проекта. Источник кода задаётся переменной окружения DJANGO_SETTINGS_MODULE. При создании Django-проекта стандартным способом, например:
$ django-admin startproject myproject
создаётся и модуль настроек. Это файл ‘myproject/myproject/settings.py’. Изменяя и дополняя его, программист настраивает проект, добавляет в него собственные и сторонние компоненты и т. д.

В простых проектах, разрабатываемых одним бэкенд-программистом, бывает вполне разумно ограничиться таким модулем настроек. Однако по мере роста проекта возникают следующие проблемы:

  1. Настройки проекта для развёртывания в боевой или тестовой среде очень отличаются от настроек, с которыми проект запускают разработчики. Например, в бою приложение требует «большой» SQL-сервер (PostgreSQL или MySQL) и дополнительную базу данных «ключ-значение» для хранения кэшируемых данных (memcached или Redis), в то время как разработчик на своём компютере привык обходиться SQLite. Зато настройки разработчика включают дополнительные модули для отладки проекта (например, debug_toolbar), которые не должны попаcть в production.
  2. Переменные, устанавливающие режим отладки в Django (DEBUG, TEMPLATE_DEBUG и др.), а также аналогичные переменные для сторонних компонентов, должны быть включены при разработке и выключены в продакшне. За этим довольно муторно следить при коммитах.
  3. В модуле settings хранятся чувствительные данные (SECRET_KEY, секреты/пароли для аутентификации приложения на различных сервисах и т. д.), которые становится небезопасно хранить в одном репозитории с кодом. Это особенно важно для open source-проектов, а также для крупных проектов, в которых доступ к кодовой базе имеет много разработчиков.

Проблемы 1 и 2 частично решает хранение в репозитории нескольких файлов настроек на разные случаи жизни и выбор нужного через установку переменной DJANGO_SETTINGS_MODULE. Недостаток такого решения в том, что данные в этих файлах почти полностью дублируются. По мере развития проекта разработчик обязан вносить одинаковые изменения в несколько различных файлов конфигурации, что утомительно, приводит к ошибкам и т. д., − короче говоря, противоречит принципу DRY.

Решение


Мой модуль settings обладает максимальной обратной совместимостью с дефолтовым ‘myproject/myproject/settings.py’: все ссылки на myproject.settings, если они действительно необходимы, остаются в силе. В то же время моё решение позволяет администратору проекта обезопасить приватные данные, а разработчикам − организовать себе наиболее комфортную среду на собственный вкус, независимо от коллег. Дополнительным плюсом является механизм наследования настроек: в локальных настройках можно получить доступ к общим настройкам.

Минус: для хранения локальных настроек нужно придумать какой-то отдельный метод, так как репозиторий использовать не получится. Решение этого вопроса обычно лежит в организационной плоскости: передавать секрет от более опытных коллег менее опытным, публиковать сэмпловый ‘local.py’ в приватном разделе wiki и т. п.

Зато мой метод крайне прост и быстр, не вмешивается в процесс парсинга настроек фреймворком и не создаёт лишних сущностей вроде специальных *.ini/*.conf-файлов с парсерами, классов настроек или модифицирующих настройки функций.

Hands-on


Вот последовательность действий по «апгрейду» классического модуля настроек (подразумевается, что код хранится в git-репозитории):

  1. Создайте в каталоге главного приложения подкаталог ‘settings’. Путь к нему будет выглядеть так: ‘myproject/myproject/settings/’.
  2. Переместите ваш старый ‘settings.py’ в созданный в п. 1 каталог ‘myproject/myproject/settings/’ и переименуйте его в ‘common.py’. Будем ссылаться на этот файл в дальнейшем как на «общие настройки».

    Если вы используете в проекте относительные пути от файла настроек, увеличьте глубину вложенности на один каталог. Например, код типа:
    BASE_DIR = dirname(dirname(abspath(__file__)))
    
    должен превратиться в
    BASE_DIR = dirname(dirname(dirname(abspath(__file__))))
    
  3. Создайте файл ‘myproject/myproject/settings/local.py’. В него сразу добавьте следующий код:
    from myproject.settings.common import *
    
    Вы можете добавить локальные настройки, начиная со следующей строки.

    Например, если вы − разработчик, и хотите использовать замечательный инструмент Django Debug Toolbar, вы можете добавить следующую строку:
    INSTALLED_APPS += ('debug_toolbar', )
    
  4. Создайте файл ‘myproject/myproject/settings/__init__.py’ и внесите в него следующий код:
    try:
        from myproject.settings.local import *
    except ImportError:
        from myproject.settings.common import *
    
    Этот вариант рассчитан на тот случай, когда настройки, содержащиеся в common.py, вполне достаточны для того, чтобы проект запустился. Это вряд ли будет соответствовать истине в большом проекте. Как минимум, из общих настроек следует изъять SECRET_KEY по соображениям безопасности.

    Если без файла локальной конфигурации запуск проекта не имеет смысла, можно не пытаться обойтись глобальными настройками, а выбросить исключение:
    try:
        from myproject.settings.local import *
    except ImportError:
        raise Exception('Please create local.py file')
    
  5. Добавьте файл ‘myproject/myproject/settings/local.py’ в исключения git. Это последний, но от этого не менее важный шаг.

Готово! Мы разбили файл настроек на общую, прототипную часть (common.py), и локальную часть, наследующую настройки от общей (local.py). Теперь всё дело за правильной декомпозицией настроек.
Tags:
Hubs:
+9
Comments22

Articles

Change theme settings