Skip to main content

Simple powerful and convenient configs for Django

Project description

LiveConfigs

LiveConfigs помогает настраивать приложение "на лету" через django-админку без перевыкатки и перезапуска. Сама конфигурация хранится в БД, но для разработчика скрыта за удобным программным интерфейсом.

Быстрый пример

Создаем настройки

class MyConfig(liveconfigs.BaseConfig):
   IS_FEATURE_ENABLED: bool = False
   NEW_FEATURE_VALUE: float = 20.4

Используем их

if MyConfig.IS_FEATURE_ENABLED:
   print('feature is enabled and feature value is', MyConfig.NEW_FEATURE_VALUE)

Меняем через админку!

Экран редактирования конфига

Термины

  • настройка, конфиг - одно типизированное именованное значение
  • класс конфига, группа настроек - настройки, объединенные в один класс python
  • топик - общая "тема" для группы настроек, по которой можно производить поиск настроек в админке. У разных групп настроек в принципе может быть один и тот же топик
  • теги - ключевые слова для быстрого поиска настроек. Одна настройка может иметь несколько тегов

Со стороны разработчика

Для разработчика настройки выглядят как статические члены-константы классов python. Их можно быстро добавить, убрать, их просто использовать (пара строк кода). Их понимает mytype и среды разработки.

За создание новых конфигов отвечает разработчик. Значения по-умолчанию хранятся в коде. В БД новые конфиги попадают при выкатке или при первом использовании.

Со стороны администратора

Значения задаются через админку django. Для удобного администрирования конфиги поддерживают

  • теги и топики для группировки и поиска
  • документацию
  • автоматическую загрузку новых конфигов в бд
  • валидацию при изменении (типы и значения)
  • сохранение даты последних изменений и чтений конфигов
  • импорт и экспорт (удобно для тестирования системы)

Экран поиска и фильтрации конфигов

Как начать пользоваться

  1. Добавьте "liveconfigs" в INSTALLED_APPS в settings:
    INSTALLED_APPS = [
        ...,
        "liveconfigs",
    ]
  1. Добавьте в settings еще несколько строк.
    # liveconfigs settings
    # Максимальная длина текста в значении конфига при которой отображать поле редактирования конфига как textinput
    # При длине текста в значении конфига большей этого значения - отображать поле редактирования конфига как textarea
    LC_MAX_STR_LENGTH_DISPLAYED_AS_TEXTINPUT = 50
    LC_ENABLE_PRETTY_INPUT = True
    LIVECONFIGS_SYNCWRITE = True    # sync write mode
    LC_CACHE_TTL = 1    # cache TTL in seconds (default = 1)
  1. Заведите себе файл собственно с конфигами, например config/config.py
from liveconfigs import models
from liveconfigs.validators import greater_than
from enum import Enum

# isort: off

# config_row_update_signal_handler begin
from django.conf import settings
from django.dispatch import receiver
from liveconfigs.signals import config_row_update_signal
from liveconfigs.tasks import config_row_update_or_create

# FIXME: Импорт приложения Celery из вашего проекта (если используете Celery)
# FIXME: Вам нужно изменить этот код, если вы используете не Celery
from celery_app import app

# isort: on

# Пример для Celery
# Реальное сохранение данных выполняет функция config_row_update_or_create
# Реализуйте отложенное сохранение удобным для вас методом
# Для Celery зарегистрируйте эту задачу в CELERY_TASK_ROUTES
# FIXME: Вам нужно изменить этот код, если вы используете не Celery
@app.task(max_retries=1, soft_time_limit=1200, time_limit=1500)
def config_row_update_or_create_proxy(config_name: str, update_fields: dict):
    config_row_update_or_create(config_name, update_fields)


@receiver(config_row_update_signal, dispatch_uid="config_row_update_signal")
def config_row_update_signal_handler(sender, config_name, update_fields, **kwargs):
    # Пример для Celery
    # При настройках для синхронного сохранения функция будет вызвана напрямую
    if settings.LIVECONFIGS_SYNCWRITE:
        config_row_update_or_create_proxy_func = config_row_update_or_create_proxy
    # При настройках для асинхронного сохранения функция будет вызвана через delay
    # FIXME: Вам нужно изменить этот код, если вы используете не Celery
    else:
        config_row_update_or_create_proxy_func = config_row_update_or_create_proxy.delay

    config_row_update_or_create_proxy_func(config_name, update_fields)


# config_row_update_signal_handler end


# тут перечислены возможные теги для настроек из вашей предметной области
class ConfigTags(str, Enum):
    front = "Настройки для фронта"
    features = "Фичи"
    basic = "Основные"
    other = "Прочее"

# тут описана сама настройка и ее мета-данные
class FirstExample(models.BaseConfig):
    __topic__ = 'Основные настройки'  # короткое описание группы настроек
    MY_FIRST_CONFIG: int = 40
    # следующие строчки необязательны
    MY_FIRST_CONFIG_DESCRIPTION = "Какая-то моя настройка"
    MY_FIRST_CONFIG_TAGS = [ConfigTags.basic, ConfigTags.other]
    MY_FIRST_CONFIG_VALIDATORS = [greater_than(5)]
    
    # вторая настройка, без метаданных
    SECOND_ONE: bool = False  
  1. Используете где-нибудь FirstExample.MY_FIRST_CONFIG как обычный int:
from config.config import FirstExample
...
if FirstExample.MY_FIRST_CONFIG > 20:
    print("Hello there!")

Просмотр и редактирование конфигов в админке django

Редактировать значения конфигов можно по адресу http://YOUR_HOST/admin/liveconfigs/configrow/

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

Автоматическая загрузка новых конфигов в БД

При первом обращении к настройке приложение проверяет, есть ли запись о них в БД. Если ее нет, то конфиг записывается в БД со значением по-умолчанию.

Если по какой-то причине вы не хотите ждать, то залить все новые конфиги в БД можно и на старте сервиса, добавив в ваш скрипт запуска вызов команды load_config:

    # какие-то старые команды
    python /app/manage.py migrate --noinput
    python /app/manage.py collectstatic --noinput

    #  НОВАЯ СТРОЧКА - загрузка конфигов в бд
    python /app/manage.py load_config

    #  сам запуск сервиса - может быть и так
    python /app/manage.py runserver_plus 0.0.0.0:8080 --insecure

Даты последнего изменения и чтения

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

Асинхронная запись

Чтобы запись последней даты чтения не тормозила вам всю систему (если,например, конфиги часто читаются разными частями кода), можно вынести ее в задачу celery. Для этого:

  1. Установите переменную LIVECONFIGS_SYNCWRITE в settings.py в False:
    LIVECONFIGS_SYNCWRITE = False   # async write mode
  1. Если используете Celery, то настройте запуск задачи config.config.config_row_update_or_create_proxy:
    CELERY_TASK_ROUTES = {
        'config.config.config_row_update_or_create_proxy': {
            'queue': 'quick', 'routing_key': 'quick'
        },
    }
  1. Если используете не Celery, то адаптируйте этот код под ваш случай

Остались вопросы?

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_liveconfigs-1.0.4.tar.gz (17.2 kB view hashes)

Uploaded Source

Built Distribution

django_liveconfigs-1.0.4-py3-none-any.whl (22.3 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page