Сочетание Python и pydantic обеспечивает мощное решение для проверки данных и настроек, что приводит к упрощению кода и сокращению усилий по отладке.

Давайте программировать!

В прошлом настройка новых сред для проектов Django была для меня источником разочарования. Однако, комбинируя подсказки типа pydantic и Python, я смог создать прочную и масштабируемую структуру, отвечающую моим потребностям.

Как описано в PEP 484, подсказки типов поддерживают статический анализ, но эти же аннотации также доступны во время выполнения. Сторонние пакеты, такие как pydantic, обеспечивают проверку типов во время выполнения, используя дополнительные метаданные в виде подсказок типов Python. Pydantic использует эти подсказки для эффективного управления метаданными настроек и выполнения проверки данных во время выполнения.

Этот учебник по pydantic продемонстрирует, как использование управления настройками pydantic с Django может оказать существенное положительное влияние на ваше приложение.

Наша конфигурация соответствует рекомендациям, описанным на сайте Twelve-Factor App:

  1. Определите непостоянные и секретные конфигурации как переменные среды.
  2. В средах разработки определите переменные среды в файле .env и добавьте .env в .gitignore.
  3. Используйте механизмы облачного провайдера для определения (секретных) переменных среды для QA, промежуточной и производственной сред.
  4. Используйте один файл settings.py, который настраивается из переменных среды.
  5. Используйте pydantic для чтения, проверки, проверки и приведения переменных среды к переменным Python, которые определяют конфигурации Django.

Кроме того, некоторые разработчики создают несколько файлов настроек, например settings_dev.py и settings_prod.py. К сожалению, этот подход плохо масштабируется. Это приводит к дублированию кода, путанице, трудно находимым ошибкам и увеличению усилий по обслуживанию.

Следуя рекомендуемым передовым методам, включение любого количества сред становится простым, четко определенным и устойчивым к ошибкам процессом. Хотя мы могли бы углубиться в более сложную конфигурацию среды, для ясности мы сконцентрируемся только на двух средах: разработке и производстве.

Как это выглядит на практике?

Управление настройками Pydantic и переменные среды

В следующем примере мы покажем, как pydantic поддерживает различную конфигурацию параметров как в среде разработки, так и в рабочей среде.

Для нашего примера приложения требуется база данных, поддерживаемая Django, поэтому нам нужно сохранить строку подключения к базе данных. Мы перемещаем информацию о конфигурации подключения к базе данных в переменную среды DATABASE_URL, используя пакет Python dj-database-url. Обратите внимание, что эта переменная имеет тип str и имеет следующий формат:

postgres://{user}:{password}@{hostname}:{port}/{database-name} 
mysql://{user}:{password}@{hostname}:{port}/{database-name} 
oracle://{user}:{password}@{hostname}:{port}/{database-name} 
sqlite:///PATH

Для нашей среды разработки мы можем выбрать экземпляр PostgreSQL, содержащийся в Docker, чтобы упростить настройку и использование, а для рабочей среды мы настроим его для использования подготовленной службы базы данных.

Еще одна переменная, которую мы хотим определить, — это логическое значение DEBUG. Флаг DEBUG в разделе Использование Django в производственной среде не рекомендуется. Он предназначен для предоставления разработчикам обратной связи во время разработки, например, для отображения подробных страниц ошибок в режиме отладки при возникновении исключения.

Различные значения для разработки и производства можно определить следующим образом:

После этого нам нужно настроить конфигурацию приложения, чтобы автоматически считывать эти значения из любой среды.

Подготовительные шаги

Чтобы применить это на практике, мы начинаем настраивать нашу среду разработки, создавая наш единственный файл .env со следующим содержимым:

DATABASE_URL=postgres://postgres:mypw@localhost:5432/mydb
DEBUG=True

Затем мы добавляем файл .env в файл .gitignore проекта. Файл .gitignore позволяет избежать сохранения потенциально конфиденциальной информации в системе управления версиями.

Хотя вышеупомянутый подход может подойти для среды разработки, он не оптимален для производственной среды, которая имеет другую спецификацию. Рекомендуется использовать секреты среды для переменных производственной среды. На таких платформах, как Heroku, эти секреты называются Config Vars и могут быть настроены с помощью панели инструментов Heroku. Затем эти секреты становятся доступными для развернутого приложения в виде переменных среды:

После этого нам нужно изменить конфигурацию приложения, чтобы автоматически считывать эти значения из среды, будь то среда разработки или производственная среда.

Настройка Django settings.py

Давайте начнем с нового проекта Django, чтобы обеспечить необходимую структуру для нашего примера. Мы создаем новый проект Django с помощью следующей команды терминала:

$ django-admin startproject mysite

Теперь у нас есть базовая структура проекта mysite. Файловая структура проекта выглядит следующим образом:

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

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

Чтобы управлять этими настройками приложения с помощью переменных среды и pydantic, добавьте этот код в начало файла settings.py:

import os
from pathlib import Path
from pydantic import (
    BaseSettings,
    PostgresDsn,
    EmailStr,
    HttpUrl,
)
import dj_database_url

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

class SettingsFromEnvironment(BaseSettings):
    """Defines environment variables with their types and optional defaults"""

    DATABASE_URL: PostgresDsn
    DEBUG: bool = False

    class Config:
        """Defines configuration for pydantic environment loading"""

        env_file = str(BASE_DIR / ".env")
        case_sensitive = True

config = SettingsFromEnvironment()

os.environ["DATABASE_URL"] = config.DATABASE_URL
DATABASES = {
    "default": dj_database_url.config(conn_max_age=600, ssl_require=True)
}
DEBUG = config.DEBUG

Этот код делает следующее:

  • Определяет класс SettingsFromEnvironment, наследуемый от класса BaseSettings pydantic.
  • Определяет DATABASE_URL и DEBUG, устанавливая их тип и необязательное значение по умолчанию, используя подсказки типа Python.
  • Определяет класс Config, указывающий pydantic искать переменные в файле .env, если они отсутствуют в переменных среды системы.
  • Преобразовывает класс Config в объект config; желаемые переменные становятся доступными как config.DATABASE_URL и config.DEBUG.
  • Определяет обычные переменные Django DATABASES и DEBUG из этих config членов.

Один и тот же код работает во всех средах, и pydantic заботится о следующем:

  • Он ищет переменные среды DATABASE_URL и DEBUG.
  • Если они определены как переменные среды, как в рабочей среде, они будут использоваться.
  • В противном случае он извлекает эти значения из файла .env.
  • Если он не находит значения, он делает следующее:
  • Для DATABASE_URL выдает ошибку.
  • Для DEBUG присваивается значение по умолчанию False.
  • Если он найдет переменную окружения, он проверит типы полей и выдаст ошибку, если какой-либо из них неверен:
  • Для DATABASE_URL он проверяет, что его тип поля является URL-адресом в стиле PostgresDsn.
  • Для DEBUG он проверяет, что его тип поля является допустимым, нестрогим пидантичным логическим значением.

Обратите внимание на явную настройку переменной среды операционной системы из значения конфигурации для DATABASE_URL. Установка os.environ["DATABASE_URL"] = config.DATABASE_URL может показаться излишней, поскольку DATABASE_URL уже определена как переменная внешней среды. Однако это позволяет pydantic анализировать, проверять и проверять эту переменную. Если переменная среды DATABASE_URL отсутствует или имеет неправильный формат, pydantic выдаст четкое сообщение об ошибке. Эти проверки ошибок бесценны, когда приложение переходит от разработки к последующим средам.

Когда переменная не определена, она может либо получить значение по умолчанию, либо вызвать сообщение об ошибке с запросом на ее определение. Эти сообщения об ошибках также указывают требуемый тип данных для переменной. Этот подход имеет дополнительное преимущество, помогая новым членам команды и инженерам DevOps определить, какие переменные необходимо определить, избегая потенциальных проблем, которые могут возникнуть, когда приложение работает без всех необходимых переменных.

Вот и все. Приложение теперь имеет удобную в сопровождении реализацию управления настройками, использующую единую версию settings.py. Прелесть этого подхода в том, что он позволяет нам указать правильные переменные среды в файле .env или любым другим желаемым способом, доступным через нашу среду хостинга.

Масштабируемый путь

Я перенял практику использования управления настройками Django вместе с пидантической типизацией во всех моих проектах Django. Этот подход привел к созданию более компактных и управляемых кодовых баз и обеспечивает структурированный и масштабируемый способ добавления новых сред. Кроме того, он создает самодокументирующийся код, что облегчает разработчикам понимание и поддержку кодовой базы.

Вот так, ребята! Надеюсь моя статья поможет вам в вашем бизнесе

Спасибо, что прочитали это! Ждем ваших комментариев и предложений 😎✌