В даній статті серії “Кращі практики розробки з Django” розкажу про власні практики із налаштування Django проекту. Тобто будемо говорити про модуль settings.py, який живе в корені проекту.

Для навчання чи тестового проекту достатньо даного єдиного модуля settings.py. Проте в реальних Django сайтах, при розробці, встановленні демо чи деплойментів на продакшин сервер, приходиться постійно оновлювати дані налаштування від сервера до сервера.

Саме тому пропоную вашій увазі кілька рекомендацій щодо покращення структури налаштувань Django проекту. А поговоримо в даній статті про:

  • основні принципи налаштувань;
  • множинні файли settings.py під різні середовища;
  • кілька файлів для опису залежностей проекту requirements.txt;
  • шляхи у модулі налаштувань.

Якщо ви розробляєте веб-сайти на Django фреймворку, тоді, впевнений, дана стаття буде вам корисною. Більшість практик ми в своїй команді запозичили від інших розробників в Django спільності, а також з книги “Two Scoops of Django”.

Почнемо із розбору основних принципів, якими керуватимемось для побудови нашої власної структури налаштувань:

Основні принципи

Для ефективної побудови структури налаштувань варто встановити основні принципи і правила, які допоможуть робити правильні рішення:

  • репозиторій коду: налаштування, як і логіка проекту, повинні знаходитись в репозиторії коду;
  • cекретні дані: виключенням до попереднього правила є секретні дані; вони не повинні знаходитись в репозиторії коду і мають налаштовуватись безпосередньо на машині, де запускається проект; до таких даних належать паролі, секретні ключі та API ключі;
  • Don’t Repeat Yourself: при побудові нової структури і підходу до налаштувань проекту важливо уникати дублікації коду та роботи програміста; це правило допоможе нам ефективніше продумати архітектуру модулів налаштувань;
  • різні налаштування для різних середовищ: в різних середовищах налаштування можуть і будуть відрізнятись; відповідно, логічно буде користуватись кількома різними файлами налаштувань; проте попереднє правило рекомендує уникати повторень; саме тому, далі в статті ми розглянемо варіанти, як, маючи різні модулі і файли, не дублювати подібних налаштувань в цих різних файлах.

При розробці веб-сайту ми, зазвичай, маємо справу із наступним мінімумом середовищ:

  • локальна розробницька машина: комп’ютер програміста, на якому відбувається розробка проекту;
  • демо, preview або staging сервер, де ми показуємо клієнту попереднє демо проекту; налаштування тут є максимально подібні до кінцевого сервера;
  • CI і/або тестовий сервер: тут ми регулярно проганяємо автоматичні тести проекту; так званий Continuous Integration (CI) підхід;
  • production або кінцевий сервер: де наш сайт обслуговує реальних користувачів.

Тепер ми готові для розбору основної ідеї впорядкування налаштувань проекту:

Множинні модулі налаштувань Django проекту

Основною ідеєю є створення не одного, а кількох модулів з налаштуваннями. На кожен окремий сервер ми створюємо окремий модуль. При цьому, щоб уникати повторень налаштувань, які співпадають на різних середовищах, ми також створюємо модуль base.py. І з інших модулів налаштувань імпортуємо ці однакові змінні.

В корені проекту ми створюємо папку settings із порожнім модулем __init__.py. В цей під-пакет набиваємо необхідні модулі під різні середовища проекту:

Модулі налаштування Джанго проекту

Множинні модулі налаштування Джанго проекту

  • base.py: тримаємо тут усі однакові змінні;
  • local.py: містить налаштування для локальної розробницької машини програміста (пізніше ми зробимо так, щоб даний файл був однаковий і підходив більшості членів команди розробки);
  • staging.py: стейджинг/preview/демо інстанс;
  • test.py: файл конфігурації для прогонки тестів;
  • production.py: налаштування продакшин сайту.

Кожен із модулів local.py, staging.py, test.py, production.py імпортує дані з base.py:

Для запуску shell чи runserver команди скрипта manage.py використовуємо опцію “–settings”, щоб передати потрібний модуль з налаштуваннями:

Також, якщо є необхідність різним розробникам працювати із різними локальними налаштуваннями (наприклад один програміст працює на лінуксі, а інший на макінтоші і там відрізняються деякі змінні середовища), тоді можна в репозиторій додавати конфігураційні файли із нікнеймами розробників. Наприклад: dev_vitaliy.py (або local_vitaliy.py). В даному модулі ми вже будемо імпортували усі змінні не з модуля base.py, а з local.py, щоб користуватися спільними налаштуваннями робочого середовища команди  і модифікувати лише необхідні речі:

Чому такі файли окремих розробників також варто тримати в репозиторії? Для того, щоб інший член команди міг легко допомогти із робочим середовищем і при потребі побачити очевидні проблеми в налаштуваннях.

***

Таким чином, маючи різні файли для налаштувань різних середовищ веб-сайту, уникатимемо масу проблем і нюансів. Одним приємним побічним ефектом такого підходу є те, що подібні умовні гілки вже не будуть потрібні у коді вашого проекту:

***

Наступним кроком розглянемо ті налаштування, які не варто тримати в репозиторії коду:

Секретні дані

Секретні дані такі як паролі та секретні Django та API ключі, не варто тримати в репозиторії коду. Адже кожен із доступом до репозиторію (особливо якщо мова йде про публічний репозиторій) матиме доступ і до секретних даних. Хорошою практикою може бути встановлення таких даних безпосередньо уже на сервері. Проте далеко не всі платформи для деплойменту веб-аплікації (“Platform-as-a-service” по типу Heroku, PythonAnywhere і т.д.) дозволяють напряму редагувати Python модулі на кінцевому сервері.

Саме тому одним із оптимальних підходів є встановлення секретних змінних в якості змінних середовища і використання цих змінних у вашому Python коді.

На операційних системах Mac та Linux змінні середовища можемо встановлювати через файли в домашній директорії .bashrc, .bash_profile чи .profile. Також, деякі із змінних (наприклад API ключі) можемо встановлювати через bin/activate скрипт вашого віртуального Python середовища. Додавши до кінця скрипта подібні команди:

На Windows змінні можна встановити через команду setx. Альтернативно, також можна додати подібну стрічку до скрипта bin/activate.bat вашого Python віртуального середовища:

На продакшині, якщо ви маєте власний фізичний чи віртуальний (VPS) сервер, тоді встановлення змінних середовища не відрізнятиметься від описаних вище способів. Тобто, залежить від операційної системи вашого кінцевого сервера.

Якщо ж ви деплоїте вашу Django аплікацію на “платформа-як-сервіс” ресурси, тоді встановлення змінних середовища в кожному із випадків може відрізнятись. Для прикладу:

  • на Gondor.io: з допомогою команди: “$ gondor env:set SECRET_KEY1=*********”;
  • на Heroku: команда “$ heroku config:add SECRET_KEY1=*********”;
  • на dotCloud: команда “dotcloud env set SECRET_KEY1=*********”;

Після того, як встановили необхідні змінні середовища, їх можна витягнути з Python коду наступним чином:

Таким чином, у всіх ваших модулях налаштувань на місцях із секретними даними, перебиваємо стрічки секретних значень на подібне присвоєння змінної:

На завершення даної секції ще одне покращення до процедури отримання змінної середовища, у випадку якщо змінна не встановлена і виникає помилка. Рекомендую скопіювати наступну функцію у свій модуль налаштувань base.py і користуватись нею для отримання змінних середовища:

Файли requirements.txt

Розподіливши налаштування проекту в окремі модулі доволі логічно буде зберігати список пакетів, на які залежить наш проект, не в одному файлі requirements.txt, а також у кількох різних файлах. Кожен окремий файл для окремого середовища.

Подібним чином створюємо директорію в корені репозиторію під назвою requirements:

Структура множинних файлів залежностей

Структура множинних файлів залежностей

У ній складаємо файли для локального розробницького середовища, для демо інстанса та для продакшина. Крім того, також маємо файл base.txt.

Як і у випадку з модулями налаштувань, коли працюємо із файлами залежностей, маємо можливість унаслідувати (запозичувати) список пакетів із базового файлу base.txt. У ньому ми зберігатимемо ті пакети і версії, які потрібні у всіх середовищах.

Наприклад, локальне середовище програміста матиме ряд девелоперських інструментів Django. На демо чи продакшині подібні пакети не лише не потрібні, але й шкідливі. Тому в local.txt можемо внести все те, що потрібно лише програмістові + запозичити усі основні пакети-залежності проекту із файлу base.txt:

Файл production.txt зазвичай використовуватиме залежності близькі до base.txt, то ж міститиме лише один рядок “-r base.txt”.

Для встановлення потрібних проекту пакетів користуємось опцією -r і вказуємо на потрібний файл. Наприклад, на локальній машині команда виглядатиме наступним чином:

Фішка: якщо не знаєте, яким файлом напередодні скористались для інсталяції залежних пакетів, тоді скористайтесь командою freeze утиліти pip, щоб отримати список поточно встановлених пакетів і версій:

Шляхи в модулях налаштувань

На завершення даної статті розглянемо спосіб роботи із шляхами у налаштуваннях проекту.

Основна ідея – це уникати захардкоджених шляхів. Натомість використовувати відносні калькульовані шляхи до папок та файлів у вашому модулі налаштувань. Таким чином, без будь-яких змін, даними налаштуваннями зможуть користуватись усі члени розробницької команди.

Ось швидкий приклад із поясненнями, як ми це робимо у наших проектах на даний час. Стандартні змінні Django проекту:

Альтернативно, щоб зменшити кількість слів і помилок, пропоную розглянути у своїй щоденній роботі бібліотеку по роботі із файловою системою Unipath. Ось як виглядатиме вищенаведений приклад переведений на Unipath:

Таким чином, ні вам, ні вашим колегам не прийдеться модифікувати дані шляхи на своїх локальних машинах. Лише домовляєтесь, що зберігаєте локальні папки із статичними та медіа ресурсами у корені проекту. Якщо ж медіа дані не повинні потрапляти у репозиторій, тоді додаєте відповідні директорії у список ігнорованих.

Фішка: Якщо хочете побачити на скільки ваші налаштування проекту відрізняються від дефолтних, користуйтесь командою diffsettings скрипта manage.py.

Підсумуємо

Отже, маємо кілька основних правил, що допоможуть гнучкіше керувати налаштуваннями проекту:

  • усі налаштування йдуть у репозиторій коду;
  • окрім секретних даних, які передаються у вигляді змінних середовища на потрібному сервері;
  • будь-який проект, який планується закидати на продакшин кінцевим користувачам, потребує множинних settings та requirements файлів; окрема пара файлів settings та requirements для окремого типу середовища (демо, локальне, продакшин і т.д.);
  • шляхи в налаштуваннях будуйте так, щоб ваші колеги по проекту, також без змін могли використовувати налаштуання вашого локального розробницького середовища.

На цьому все. У наступній статті даної серії поговоримо про кращі практики при роботі з базою даних та Django моделями.

 

А які фішки ви використовуєте в налаштуванні Django проектів?