Класс Config() модуля flask в Python
Объект Config работает точно так же, как словарь dict , но дает возможность заполнять его из файлов или специальных словарей. Есть два общих шаблона для заполнения конфигурации.
Либо можно залить конфиг из конфигурационного Python файла:
app.config.from_pyfile('yourconfig.cfg')
Или, в качестве альтернативы, можно определить параметры конфигурации в модуле, который вызывает app.config.from_object() , или указать путь импорта к модулю, который должен быть загружен. Также можно указать ему использовать тот же модуль и с его помощью указать значения конфигурации непосредственно перед вызовом:
DEBUG = True SECRET_KEY = 'development key' app.config.from_object(__name__)
В обоих случаях (загрузка из любого файла Python или загрузка из модулей) в конфигурацию добавляются только ключи записанные в верхнем регистре. Это позволяет использовать строчные значения в файле конфигурации для временных значений, которые не добавляются в конфигурацию, или определять ключи конфигурации в том же файле, который реализует веб-приложение.
Наиболее интересный способ загрузки конфигураций — это использование переменной окружения, указывающей на файл:
app.config.from_envvar('YOURAPPLICATION_SETTINGS')
В этом случае перед запуском приложения необходимо установить эту переменную среды окружения в файл, который нужно использовать. В Linux и OS X используйте оператор export :
export YOURAPPLICATION_SETTINGS='/path/to/config/file'
В Windows используйте оператор set .
Методы объекта Config .
- Config.from_envvar() загружает конфигурацию из переменной среды,
- Config.from_file() обновляет конфигурацию из файла,
- Config.from_json() обновляет конфигурацию из файла JSON,
- Config.from_mapping() обновляет конфигурацию из словаря,
- Config.from_object() обновляет конфигурацию из объекта,
- Config.from_pyfile() обновляет конфигурацию из файла Python,
- Config.get_namespace() обновляет конфигурацию из окружения.
Config.from_envvar(variable_name, silent=False) :
Метод Config.from_envvar() загружает конфигурацию из переменной среды, указывающей на файл конфигурации. Это просто ссылка с более приятными сообщениями об ошибках для этой строки кода.
- variable_name : имя переменной окружения;
- silent : если не нужны сообщения об ошибках для отсутствующих файлов, установите значение True .
app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
Возвращает True , если можно загрузить конфигурацию, в противном случае False .
Config.from_file(filename, load, silent=False, text=False) :
Метод Config.from_file() обновляет значения в конфигурации из файла, который загружается с помощью параметра load. Загруженные данные передаются методу Config.from_mapping() .
- filename : путь к файлу с данными. Это может быть абсолютный путь или относительно корневого пути конфигурации.
- load : вызываемый объект, который принимает дескриптор файла и возвращает словарный объект с загруженными данными из файла.
- silent=False : если True , то будет игнорировать файл, если он не существует.
- text=False : указывает, что синтаксический анализатор вместо текста хочет двоичный файл (добавлен в Flask 2.3.0).
import toml app.config.from_file("config.toml", load=toml.load)
Возвращает True , если можно загрузить конфигурацию, в противном случае False .
- В версии Flask 2.3.0. добавлен аргумент text=False
Config.from_json(filename, silent=False) :
Метод Config.from_json() обновляет значения в конфигурации из файла JSON. Загруженные данные передаются методу Config.from_mapping() .
- filename : путь к файлу JSON. Это может быть абсолютный путь или относительно корневого пути конфигурации.
- silent : если True , то будет игнорировать файл, если он не существует.
Не рекомендуется использовать этот метод, начиная с версии 2.0.0, будет удалено в Flask 2.1. Вместо него используйте Config.from_file() .
Config.from_mapping(mapping=None, **kwargs) :
Метод Config.from_mapping() обновляет конфигурацию из словаря, например update() , игнорируя элементы с именами в нижнем регистре.
Config.from_object(obj) :
Метод Config.from_object() обновляет значения конфигурации из данного объекта obj . Объект obj может быть одного из следующих двух типов:
- строка: в этом случае будет импортирован объект с таким именем.
- Фактическая ссылка на объект: этот объект используется напрямую
Объекты обычно представляют собой модули или классы. Метод Config.from_object() загружает только атрибуты модуля/класса, имена которых записаны в верхнем регистре. Объект dict не будет работать с этим методом, потому что ключи словаря не являются атрибутами класса dict .
Пример модульной конфигурации:
app.config.from_object('yourapplication.default_config') from yourapplication import default_config app.config.from_object(default_config)
Перед загрузкой, с объектом ничего не происходит. Если объект является классом и имеет атрибуты @property , то его необходимо создать перед передачей в этот метод.
Эту функцию следует использовать не для загрузки фактической конфигурации, а для загрузки значений конфигурации по умолчанию. Фактическая конфигурация должна быть загружена с помощью Config.from_pyfile() и в идеале из места, не входящего в пакет, поскольку пакет может быть установлен в масштабе всей системы.
Пример конфигурации на основе классов с использованием Config.from_object() смотрите в разделе «Хранение и загрузка конфигураций Flask».
Config.from_pyfile(filename, silent=False) :
Метод Config.from_pyfile() обновляет значения в конфигурации из файла Python. Эта функция ведет себя так, как если бы файл был импортирован как модуль с помощью функции Config.from_object() .
- filename : имя файла конфигурации. Это может быть либо абсолютное имя файла, либо имя файла относительно корневого пути.
- silent : если True , то будет игнорировать файл, если он не существует.
Возвращает True , если можно загрузить конфигурацию, в противном случае False .
Config.get_namespace(namespace, lowercase=True, trim_namespace=True) :
Метод Config.get_namespace() возвращает словарь, содержащий подмножество параметров конфигурации, соответствующих указанному пространству имен/префиксу. Пример использования:
Parameters- namespace : пространство имен конфигурации.- lowercase : флаг ( bool ), указывающий, должны ли ключи результирующего словаря быть строчными.- trim_namespace : флаг ( bool ), указывающий, не должны ли ключи результирующего словаря включать пространство имен.
app.config['IMAGE_STORE_TYPE'] = 'fs' app.config['IMAGE_STORE_PATH'] = '/var/app/images' app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com' image_store_config = app.config.get_namespace('IMAGE_STORE_')\ print(image_store_config) # # 'type': 'fs', # 'path': '/var/app/images', # 'base_url': 'http://img.website.com' # >
Метод полезен, когда параметры конфигурации отображаются непосредственно на ключевые аргументы в функциях или конструкторах классов.
- КРАТКИЙ ОБЗОР МАТЕРИАЛА.
- Пример структуры приложения Flask как пакета Python
- Модульные приложения на схемах blueprint во Flask Python
- Фабрика веб-приложений модуля Flask
- Представления в веб-приложении на Flask Python
- Правила составления URL-маршрутов во Flask Python
- Использование шаблонизатора Jinja2 в приложении Flask Python
- Пользовательские страницы HTTP-ошибок на Flask Python
- Выполнение кода до или после запроса во Flask Python
- Загрузка файлов на сервер во Flask Python
- Всплывающие сообщения в приложении на Flask Python
- Извлечение данных из запроса во Flask Python
- Хранение и загрузка конфигураций Flask
- Параметры/ключи конфигурации, используемые во Flask
- Папки экземпляров приложений на Flask
- Контекст веб-приложения на Flask
- Контекст запроса приложения на Flask
- Ведение журнала логов в приложении Flask Python
- Собственные декораторы в приложении Flask Python
- Класс Config() модуля flask
- Функция redirect модуля flask
- Функция url_for() модуля flask
- Прокси-объект current_app() модуля flask
- Функция abort() модуля flask
- Отладочные сигналы приложения Flask
- Работа с cookie в приложении на Flask Python
- Безопасность веб-приложения на Flask
- Асинхронность в веб-приложении на Flask
- Использование URL-процессора в приложениях на Flask Python
- Диспетчеризация приложений на Flask
- Функция make_response модуля flask
- Доступность контекстов запроса/приложения во Flask Python
- Декоратор @route() и метод add_url_rule() приложения Flask Python
- Функция send_file() модуля flask
- Функция send_from_directory() модуля flask
- Как обслуживать статические файлы в Flask Python
- Функция render_template() модуля flask
- Класс Markup() модуля flask
- Отложенная загрузка представлений в приложении Flask Python
- Сессии/сеансы sessions модуля flask
- Глобальный объект flask.g в приложении Flask Python
- Класс Request() модуля flask
- Класс Response() модуля flask
- Класс Flask() модуля flask
- Тестирование приложений на Flask
- Использование SQLite 3 в приложении Flask Python
- Генерация своей капчи на сайте Flask
- Использование модуля WTForms в приложении Flask Python
- Расширение Flask-Caching для приложения Flask
- Расширение Flask-Assets, управление статикой приложения
- Расширение Flask-WTF для приложения Flask
- Расширение Flask-SQLAlchemy для приложения Flask
- Расширение Flask-Paginate для приложения Flask
- Расширение Flask-Mail для приложения Flask
- Расширение Flask-APScheduler
- Связка Nginx + Gunicorn + Gevent + Flask Python
- Как передать переменную NGINX во Flask environ
- Защита приложения/сайта от DDoS атак
Python: конфигурация проекта без боли
Расскажу о проделанном пути, чтобы найти идеальный, для моих целей, инструмент конфигурирования проекта и о создании легковесной библиотеки bestconfig, впитавшей в себя преимущества изложенных подходов.
В статье речь пойдет только о локальных способах хранения настроек, здесь не разбираются случаи загрузки из сети.
После создания проекта рано или поздно возникает вопрос: куда записывать номер версии, где хранить токены, пароли, настройки, каким форматом файлов конфигурации воспользоваться: .json , .yaml , .env, .cfg , .ini или просто создать config.py и записывать туда переменные?
Для каждого из перечисленных вариантов есть библиотека на python, приведу примеры самых популярных форматов.
ENV
Переменные окружения могут передаваться программе напрямую командным интерпретатором: они записаны в .bashrc , выполнена команда export , или просто указаны в интерфейсе хостинга. Для того, чтобы их явно указать, удобно использовать .env файлы в директории проекта. Если прописать .env в . gitignore можно сложить туда все ключи и не боятся их опубликовать, в то время как остальные настройки будут в другом месте для использования в продакшн окружении
VERSION=2.5.11 PG_USER=postgres PG_DATABASE=my_project
Библиотека dotenv отлично справляется с задачей подгрузки таких файлов. Все переменные сразу попадают в os.environ
from dotenv import load_dotenv import os load_dotenv() print(os.getenv('VERSION'))
YAML
В последнее время стал популярен формат .yml , как один из самых приятных для чтения человеком
version: 2.5.11 logger: level: INFO format: '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
Открываем файл из кода
from yaml import load with open('config.yml', 'r') as f: data = load(f) print(data['version'])
JSON
Формат чаще используется для коммуникации между сервисам, например между фронтом и беком, как компактный, но в то же время понятный человеку. Но задать в нем некоторые настройки тоже можно
import json with open('config.json', 'r') as f: data = json.load(f) print(data['version'])
PY
В файле с расширением .py объявляем все необходимые переменные. У данного подхода есть преимощество — можно некоторые значения вычислять на ходу: инкриментировать номер сборки, менять хост в зависимости от режима: DEBUG или RELEASE и тд.
VERSION = '2.5.11' PG_DATABASE = 'postgres' PG_PORT = 5432
Осталось только импортировать этот файл там, где он нужен
from config import VERSION print(VERSION)
INI
[DEFAULT] version = '2.5.11' [postgres] user = "postgres" database = "my-project"
import configparser config = configparser.ConfigParser() config.read('settings.ini') print(config["version"])
Все просто, разве нет?
Самое интересное начинается, когда в проекте появляется несколько источников конфигов. Например статичные настройки лежат в config.yml , токены и пароли в переменных окружения и .env , некоторые записаны в файле env_file , используемом докером, часть значений нужно переопределить из кода, так как они заранее не известны, часть извлечь из аргументов программы.
Это ведет за собой менее красивый код, который обязан учитывать особенности хранения, приходится задумаваться, откуда мы берем очередное значения настроек, появляется несогласованность, ведь в одних местам мы обращаеся к os.environ , в других к глобальному словарю, в третьих, к сторонней библиотеке.
BestConfig
Блуждая по просторам всемирной паутины, идеального решения я не нашел и создал очень простую и удобную библиотеку, умеющую бороться в вышеперечисленными проблемами.
Поставил целью уменьшить количество кода чтения конфигов почти до нуля, но в тоже время оставить гибкость и возможность подкрутки под более специфичные задачи. Итак, давайе посмотрим, как импортировать например config.yml
from bestconfig import Config config = Config() print(config['version'])
И да, это все, что нужно сделать. Глобальный объект config уже будет содержать все необходимое. А теперь по порядку.
Что происходит при создании Config() :
- Запускается поиск файлов, похожих на конфиги: любые комбинации имени conf, config, configuration, setting, settings с расширениями yml, yaml, json, ini, cfg, env в текущей директории и в папках выше, вплодь до корня проекта. Также в хранилище добавляются переменные окружения
- Исходя из формата файла производится импорт содержимого
- Создается класс ConfigProvider , предоставляющий универсальный доступ ко всему содержимому
print(isinstance(Config(), ConfigProvider)) # True
Посмотрим на примерах, в чем же «универсальность» объекта config
Обращение по ключу
print(config.get('version')) # При отсутствии возвращает None print(config['verions']) # При отсутствии бросает KeyError print(config.version) # Тоже может бросить KeyError # Вложенные структуры print(config.postgres.port) print(config['postgres.port']) print(config.get('postgres.port')) # Очевидно, глубина вложенности не ограничена
Иногда мы хотим быть уверены, что значение принадлежит определенному типу
type(config.int('limit')) # int type(config.dict('logger')) # dict type(config.list('admins')) # list # И тд: float, str
Преимущество такого подхода в том, что среда разработки сразу узнает тип и будет указывать на ошибки, также это дополнительная валидация самого конфига.
Иногда хочется где-нибудь в самом начале программы или скрипта убедиться, что необходимые переменные заданы, для этого предусмотренна специальная функция
config.assert_contains('key') # Что эквивалентно assert config.get('key')
Класс ConfigProvider наследуется от dict , поэтому его можно спокойно передавать в сторонние библиотеки.
import logging.config from config import config logging.config.dictConfig(config['logging']) print(config) # Выведется как словарь
Модификация
from argparse import ArgumentParser from config import config if __name__ == '__main__': # Парсим аргументы командной строки parser = ArgumentParser() parser.add_argument('log_level') args = parser.parse_args() # Обновляем общий конфиг config.insert()
Помимо словаря метод insert принимает названия файлов (с абсолютным или относильным путем) любого из поддерживаемых расширений
config.insert('logging.json') # Кроме обычных методов dict-а есть set config.set('key', 'value')
Выше я приводил пример, в котором конфиг переменные объявляются прямо в .py файле. Если в проекте уже используется такой вариант, необязательно всё менять, на этот случай есть метод update_from_locals
from config import config VERSION = '2.5.11' LOGGING_LEVEL = 'INFO' config.update_from_locals()
В питоне есть встроенная функци locals() , она возвращает словарь локальных переменных, имеено ее и использует данный метод. Там, конечно, рассматриваются добавляемые объекты и лишние отсеиваются (подробнее в документации).
Кастомизация
По умолчанию Config() делает довольно много всего, с целью быть универсальным, но содежит ряд аргументов, регулирующих это поведение.
# Исключить из списка по умолчанию некоторые файлы Config(exclude=['server/setting.json']) # Указать свои пути Config('my-config.json', '../other-config.yml', 'app/settings.cfg') # Импортировать только config.yml и кидать исключение при его отсутствии # Игнорировать весь список по умолчанию Config('config.yml', exclude_default=True, raise_on_absent=True)
Установка
pip install bestconfig
Best practices
Обобщу процесс взаимодействия с конфигами с использованием библиотеки bestconfig.
- Статичные настройки, не содержащие ключей лежат в файле config.yml в корне проекта
- Переменные окружения и ключи задаются в .env и игнорируются системой контроля версий
- Файл config.py содержит создает класс Config и выполняет другие настройки (например логгирование, версия проекта, обработка параметров запуска и тд)
- В других местах проекта делаем from config import config и используемый нужные данные удобным образом
Резюме
Библиотека создана чтобы максимально упростить распространенную задачу по обращению к файлам настроки, ее основные фичи и особенности:
- Поддержка множества форматов файлов
- Интерфейс доступа к данным «на любой вкус» (по ключу, через точку, через get и тд)
- Маленький вес (примерно 15 кб)
- Большое тестовое покрытие
- Чистый, типизированный, расширяемый python код на модульной архитектуре
- Открытость к изменениям и дополнениям (pull request-ы приветствуются)
Есть и недостатки:
- У проекта появляются лишние зависимости. Например вы не используете yaml, однако библиотека подтягивает pyyaml
- Захват лишнего. Вы можете написать Config() и даже не обратить внимание, сколько всего попало в config, одни переменные окружения чего стоят — их может быть очень много. И вывод print(config) становится абсолютно не читаемым
Теперь, при создании нового sandbox проекта или усложении текущего еще одним видом конфигурационных файлов, вы можете выбрать из своего арсенала еще один инструмент!
- Python
- Совершенный код
Конфигурационные файлы в Python
Конфиги. Все хранят их по разному. Кто-то в .yaml , кто-то в .ini , а кто-то вообще в исходном коде, подумав, что «Путь Django» с его settings.py действительно хорош.
В этой статье, я хочу попробовать найти идеальный (вероятнее всего) способ хранения и использования конфигурационных файлов в Python. Ну, а также поделиться своей библиотекой для них 🙂
Попытка №1
А что насчёт того чтобы хранить конфигурацию в коде? Ну, а что, вроде удобно, да и новых языков не придётся изучать. Существует множество проектов, в которых данный способ используется, и хочу сказать, вполне успешно.
Типичный конфиг в этом стиле выглядит так:
# settings.py TWITTER_USERNAME="johndoe" TWITTER_PASSWORD="johndoespassword" TWITTER_TOKEN=". "
Выглядит неплохо. Только одно настораживает, почему секьюрные данные хранятся в коде? Как мы это коммитить будем? Загадка. Разве что вносить наш файл в .gitignore , но это, конечно, вообще не решение.
Да и вообще, почему хоть какие-то данные хранятся в коде? Как мне кажется код, он на то и код, что должен выполнять какую-то логику, а не хранить данные.
Данный подход, на самом деле используется много где. В том же Django. Все думают, что раз это самый популярный фреймворк, который используется в самом Инстаграме, то они то уж плохое советовать не будут. Жаль, что это не так.
Попытка №2
Ладно, раз уж мы решили, что хранить данные в коде — не круто, то давайте искать альтернативу. Для конфигурационных файлов изобретено немалое количество различных форматов, в последнее время набирают большую популярность toml .
Но мы начнём с того, что нам предлагает сам Python — .ini . В стандартной библиотеке имеется библиотека configparser .
Наш конфиг, который мы уже писали ранее:
# settings.ini [Twitter] username="johndoe" password="johndoespassword" token=". "
А теперь прочитаем в Python:
import configparser # импортируем библиотеку config = configparser.ConfigParser() # создаём объекта парсера config.read("settings.ini") # читаем конфиг print(config["Twitter"]["username"]) # обращаемся как к обычному словарю! # 'johndoe'
Все проблемы решены. Данные хранятся не в коде, доступ прост. Но… а если нам нужно читать другие конфиги, ну там json или yaml например, или все сразу. Конечно, есть json в стандартной библиотеке и pyyaml , но придётся написать кучу (ну, или не совсем) кода для этого.
Попытка №3
А сейчас, я хотел бы показать Вам свою библиотеку, которая призвана решить все эти проблемы (ну, или хотя бы уменьшить ваши страдания :)).
Называется она betterconf и доступна на PyPi.
Установка так же проста, как и любой другой библиотеки:
pip install betterconf
Изначально, наш конфиг представлен в виде класса с полями:
# settings.py from betterconf import Config, field class TwitterConfig(Config): # объявляем класс, который наследуется от `Config` username = field("TWITTER_USERNAME", default="johndoe") # объявляем поле `username`, если оно не найдено, выставляем стандартное password = field("TWITTER_PASSWORD", default="johndoespassword") # аналогично token = field("TWITTER_TOKEN", default=lambda: raise RuntimeError("Account's token must be defined!") # делаем тоже самое, но при отсутствии токенавозбуждаем ошибку cfg = TwitterConfig() print(cfg.username) # 'johndoe'
По умолчанию, библиотека пытается взять значения из переменных окружения, но мы также можем настроить и это:
from betterconf import Config, field from betterconf.config import AbstractProvider import json class JSONProvider(AbstractProvider): # наследуемся от абстрактного класса SETTINGS_JSON_FILE = "settings.json" # путь до файла с настройками def __init__(self): with open(self.SETTINGS_JSON_FILE, "r") as f: self._settings = json.load(f) # открываем и читаем def get(self, name): return self._settings.get(name) # если значение есть - возвращаем его, иначе - None. Библиотека будет выбрасывать свою исключением, если получит None. provider = JSONProvider() class TwitterConfig(Config): username = field("twitter_username", provider=provider) # используем наш способ получения данных # . cfg = TwitterConfig() # .
Из этого примера следует, что мы можем применять различные провайдеры для получения данных. И это действительно иногда бывает удобно, говорю из личного опыта.
Хорошо, а что если у нас в конфигах есть булевые значения, или числа, они же в итоге будут все равно приходить в строках. И для этого есть решение:
from betterconf import Config, field # из коробки доступно всего 2 кастера from betterconf.caster import to_bool, to_int class TwitterConfig(Config): # . post_tweets = field("TWITTER_POST_TWEETS", caster=to_bool) # .
Таким образом, все похожие на булевые типы значения (а именно true и false будут преобразованы в питоновский bool . Регистр не учитывается.
Свой кастер написать также легко:
from betterconf.caster import AbstractCaster class DashToDotCaster(AbstractCaster): def cast(self, val): return val.replace("-", ".") # заменяет тире на точки to_dot = DashToDotCaster() # .
Итоги
Таким образом, мы пришли к выводу, что хранить настройки в исходных кодах — не есть хорошо. Для этого уже придуманы различные форматы. Ну, а вы познакомились с ещё одной полезной (как я считаю :)) библиотекой.
P.S
Да, также можно было включить и Pydantic , но я считаю, что он слишком НЕлегковесный для таких задач.
Обработка конфигурации Flask¶
Приложения требуют настройки. Здесь описаны различные настройки, которые можно менять в зависимости от окружения, в котором работает приложение: переключение режима отладки, настройки секретного ключа и т.п.
Flask спроектирован так, что обычно требует настройки при запуске приложения. Вы можете вшить настройки в код, что не так уж плохо для многих небольших приложений, но имеются способы лучше.
Вне зависимости от того, каким образом загружена конфигурация, существует объект конфигурации, содержащий загруженные параметры: атрибут config объекта Flask . Это место, где Flask содержит свои настройки, а также то место, куда расширения могут поместить собственные настройки. Но здесь можно размещать и конфигурацию вашего приложения.
Основы конфигурации¶
config на самом деле является подклассом словаря и может изменяться точно так же, как и любой словарь:
app = Flask(__name__) app.config['DEBUG'] = True
Некоторые параметры конфигурации передаются в объект Flask , которые тоже можно читать и писать:
app.debug = True
Для обновления нескольких ключей за раз можно воспользоваться методом словаря dict.update() :
app.config.update( DEBUG=True, SECRET_KEY='. ' )
Встроенные параметры конфигурации¶
Сам Flask использует следующие параметры конфигурации:
| DEBUG | Включить/выключить режим отладки. |
| TESTING | Включить/выключить режим тестирования. |
| PROPAGATE_EXCEPTIONS | Явное включение или отключение исключений. Если не задано или явным образом задано значение None , то подразумевается истина, если истиной является TESTING или DEBUG . |
| PRESERVE_CONTEXT_ON_EXCEPTION | По умолчанию в режиме отладки при возникновении исключения контекст запроса не извлекается из стека, позволяя отладчику анализировать данные. Такое поведение можно отключить с помощью этого параметра. Также можно воспользоваться этим параметром для его принудительного включения, если это может помочь в отладке приложений в эксплуатации (однако, это не рекомендуется). |
| SECRET_KEY | Секретный ключ. |
| SESSION_COOKIE_NAME | Имя переменной (cookie) браузера для хранения сеанса. |
| SESSION_COOKIE_DOMAIN | Домен переменной браузера, используемой для хранения сеанса. Если не задан, переменная браузера будет действительной для всех поддоменов SERVER_NAME . |
| SESSION_COOKIE_PATH | Путь к переменной браузера, используемой для хранения сеанса. Если не задан, переменная браузера будет действительной для всех APPLICATION_ROOT , если не задано значение ‘/’ . |
| SESSION_COOKIE_HTTPONLY | Указывает, должен ли у переменной браузера устанавливаться флаг httponly (что защищает переменную от доступа со стороны скриптов, работающих внутри браузера — прим. перев. ). По умолчанию — True . |
| SESSION_COOKIE_SECURE | Указывает, должен ли у переменной браузера устанавливаться флаг secure (что позволяет передавать переменную только по защищённому протоколу HTTPS — прим. перев. ). По умолчанию — False . |
| PERMANENT_SESSION_LIFETIME | Непрерывное время жизни сеанса, как объект datetime.timedelta . Начиная с Flask 0.8 этот параметр может быть задан в виде целого числа с количеством секунд. |
| SESSION_REFRESH_EACH_REQUEST | Этот флаг контролирует, как будут обновляться постоянные сессии. Если установлен в True (по умолчанию), cookies будут обновляться при каждом запросе, что автоматически подтолкнёт вперёд окончание их срока жизни. Если установлен в False , заголовок set-cookie посылается только в случае внесения изменений в сессию. Не влияет на не постоянные сессии. |
| USE_X_SENDFILE | Включить/отключить x-sendfile. (При использовании этой возможности представление может вернуть специально сформированный ответ со ссылкой на статический файл. Получив такой ответ от представления, веб-сервер отдаёт клиенту вместо ответа представления сам статический файл, найдя его по ссылке в локальной файловой системе. Это позволяет перенести нагрузку по отдаче больших файлов на веб-сервер, если перед отдачей файла представление должно решить, можно ли отдавать этот файл клиенту и какой именно файл нужно отдать по этой ссылке — прим. перев. ) |
| LOGGER_NAME | Имя средства журналирования. |
| SERVER_NAME | Имя и номер порта сервера. Необходимо для поддержки поддоменов (например: ‘myapp.dev:5000’ ). Отметим, что localhost не поддерживает поддомены, поэтому установка параметра в значение “localhost” не поможет. Настройка SERVER_NAME также по умолчанию включает генерацию URL’ов без контекста запроса, но с контекстом приложения. |
| APPLICATION_ROOT | Если приложение не занимает целый домен или поддомен, с помощью этого параметра можно задать путь к настроенному приложению. Значение этого параметра используется в качестве пути к переменной браузера для хранения сеанса. Если используются домены, значением этого параметра должно быть None . |
| MAX_CONTENT_LENGTH | Если задать значение в байтах, Flask будет отклонять входящие запросы, объём содержимого которых больше этого значения, возвращая код статуса 413. |
| SEND_FILE_MAX_AGE_DEFAULT : | По умолчанию задаёт время кэширования файла для использования совместно с send_static_file() (обработчик статических файлов по умолчанию) и send_file() , в секундах. Заменить это значение для каждого файла индивидуально можно с помощью обработчика get_send_file_max_age() Flask или Blueprint . По умолчанию — 43200 (12 часов). |
| TRAP_HTTP_EXCEPTIONS | Если True , Flask не выполняет обработчиков ошибок исключений HTTP, но вместо этого трактует исключение как любое другое и передаёт исключение выше. Этот параметр полезен для отладки сложных случаев, когда нужно найти, где именно произошло исключение HTTP. |
| TRAP_BAD_REQUEST_ERRORS | Внутренние структуры данных Werkzeug, работающие с данными запроса порождают ошибки с особым ключом, также являющимся исключением запроса. Также, многие операции могут неявно приводить к исключениям BadRequest в случае ошибок целостности. Поскольку для отладки важно знать, где именно произошла ошибка, этот флаг может использоваться для отладки в подобных случаях. Если этот параметр истинен ( True ), произойдёт обычная выдача результата трассировки. |
| PREFERRED_URL_SCHEME | Схема, которую нужно использовать для генерации URL’ов, если она не указана явно. По умолчанию — http . |
| JSON_AS_ASCII | По умолчанию Flask сериализует объекты к JSON, представленному в виде ASCII. Если False , Flask не будет кодировать в ASCII, а выводимые строки будут как есть, то есть в виде строк в формате unicode. Затем, json-ификация автоматически переведёт их к кодировке utf-8 для дальнейшей доставки для экземпляра. |
| JSON_SORT_KEYS | По умолчанию Flask сериализует объекты JSON таким способом, что ключи становятся упорядоченными. Это делается, чтобы гарантировать, что независимо от значения хэша словаря, возвращаемое значение будет таким, чтобы не замусоривать внешние HTTP- кэши. Вы можете переопределить поведение по умолчанию через изменение этой переменной. Это не рекомендовано, но может дать вам выигрыш в производительности ценой худшей кэшируемости данных. |
| JSONIFY_PRETTYPRINT_REGULAR | Если True (по умолчанию), ответы json-ификации будут распечатаны, если они не запрашивались объектом XMLHttpRequest (который контролируется заголовком X-Requested-With ) |
| TEMPLATES_AUTO_RELOAD | Flask проверяет, был ли изменён шаблон каждый раз, когда он запрашивается, и перезагружает его в случае такой необходимости. Однако это происходит ценой увеличения дискового ввода-вывода, и может появиться жизненная необходимость отключить данную особенность путём установки этого ключа в False . Данная опция не оказывает влияния при работе в режиме отладки. |
Подробнее о SERVER_NAME
SERVER_NAME — это параметр, который используется для поддержки поддоменов. Flask не может догадаться о том, какая часть доменного имени является поддоменом, не зная имя сервера. Этот же параметр используется для настройки переменной браузера, в которой хранится сеанс.
Помните, что не только Flask не может узнать поддомен, ваш веб-браузер тоже не может. Большинство соверменных браузеров не разрешают междоменные переменные браузера, если в имени сервера нет точек. Поэтому если имя сервера ‘localhost’ , вы не сможете задать переменную браузера для ‘localhost’ и каждого из его поддоменов. В этом случае выберите другое имя сервера, например ‘myapplication.local’ и добавьте это имя и поддомены, которые вы хотите использовать, в файл hosts или настройте локальный bind.
Добавлено в версии 0.4: LOGGER_NAME
Добавлено в версии 0.5: SERVER_NAME
Добавлено в версии 0.6: MAX_CONTENT_LENGTH
Добавлено в версии 0.7: PROPAGATE_EXCEPTIONS , PRESERVE_CONTEXT_ON_EXCEPTION
Добавлено в версии 0.8: TRAP_BAD_REQUEST_ERRORS , TRAP_HTTP_EXCEPTIONS , APPLICATION_ROOT , SESSION_COOKIE_DOMAIN , SESSION_COOKIE_PATH , SESSION_COOKIE_HTTPONLY , SESSION_COOKIE_SECURE
Добавлено в версии 0.9: PREFERRED_URL_SCHEME
Добавлено в версии 0.10: JSON_AS_ASCII , JSON_SORT_KEYS , JSONIFY_PRETTYPRINT_REGULAR
Добавлено в версии 1.0: SESSION_REFRESH_EACH_REQUEST
Добавлено в версии 1.0: TEMPLATES_AUTO_RELOAD
Задание конфигурации с помощью файлов¶
Конфигурация становится более удобной, если разместить её в отдельном файле. Лучше, если он находится за пределами пакета с приложением. Это позволяет создавать пакеты и распространять приложения с помощью различных инструментов обработки пакетов ( distribute-deployment ) и впоследствии — изменять конфигурацию.
Далее показан обычный пример::
app = Flask(__name__) app.config.from_object('yourapplication.default_settings') app.config.from_envvar('YOURAPPLICATION_SETTINGS')
Сначала грузится конфигурация из модуля yourapplication.default_settings , а затем её значения заменяет содержимое файла, указанного в переменной окружения YOURAPPLICATION_SETTINGS . Эта переменная окружения может быть задана в Linux или OS X при помощи команды export оболочки перед запуском сервера:
$ export YOURAPPLICATION_SETTINGS=/path/to/settings.cfg $ python run-app.py * Running on http://127.0.0.1:5000/ * Restarting with reloader.
В системах Windows воспользуйтесь встроенной командой set :
>set YOURAPPLICATION_SETTINGS=\path\to\settings.cfg
Файлы конфигурации являются обычными файлами Python. В объект конфигурации сохраняются только переменные с именами в верхнем регистре, так что убедитесь в том, что имена ваших параметров заданы в верхнем регистре.
Вот пример файла конфигурации:
# Пример конфигурации DEBUG = False SECRET_KEY = '?\xbf,\xb4\x8d\xa3"\x9c\xb0@\x0f5\xab,w\xee\x8d$0\x13\x8b83'
Убедитесь в том, что файл загружается как можно раньше, чтобы расширения могли получить доступ к собственным настройкам при запуске. Существуют другие методы загрузки объекта конфигурации из отдельных файлов. За более полной информацией обратитесь к документации объекта Config .
Лучшие способы задания конфигурации¶
Недостаток описанного выше подхода заключается в усложнении тестирования. Нет стопроцентного способа решения этой проблемы, но вот несколько рекомендаций опытных пользователей:
- Создайте ваше приложение внутри функции и зарегистрируйте в ней blueprint’ы. Таким образом вы можете создать несколько экземпляров вашего приложения с разными конфигурациями, что значительно упростит модульное тестирование. Вы можете воспользоваться функцией, чтобы передать в неё необходимую конфигурацию.
- Не пишите код, которому требуется конфигурация при импорте. Если ограничиться чтением конфигурации по запросу, возможно будет переконфигурировать объект позже.
Режим разработки и режим эксплуатации¶
Большинству приложений нужно более одной конфигурации. По меньшей мере нужна отдельная конфигурация для рабочего сервера и ещё одна для разработки. Простейший способ управления ими — это создать конфигурацию по умолчанию, которая загружается всегда и которую можно поместить в систему управления версиями, и частичные конфигурации, которые заменяют необходимые значения следующим образом:
app = Flask(__name__) app.config.from_object('yourapplication.default_settings') app.config.from_envvar('YOURAPPLICATION_SETTINGS')
Теперь просто создайте отдельный файл config.py , выполните команду export YOURAPPLICATION_SETTINGS=/path/to/config.py и готово. Однако, существуют альтернативные способы. Например, можно воспользоваться импортом и подклассами.
В мире Django распространён следующий способ: сделать явный импорт конфигурации, добавив строку from yourapplication.default_settings import * в начале файла, а затем заменить значения вручную. Можно сделать также, затем взять из переменной окружения вида YOURAPPLICATION_MODE необходимый режим — production , development и т.п., а затем импортировать заранее определённые файлы, основываясь на этом значении.
Другой любопытный способ — воспользоваться классами и наследованием конфигурации:
class Config(object): DEBUG = False TESTING = False DATABASE_URI = 'sqlite://:memory:' class ProductionConfig(Config): DATABASE_URI = 'mysql://user@localhost/foo' class DevelopmentConfig(Config): DEBUG = True class TestingConfig(Config): TESTING = True
Для включения такой конфигурации, вам просто нужно вызвать from_object() :
app.config.from_object('configmodule.ProductionConfig')
Есть много разных способов, которые можно выбрать для управления файлами конфигурации. Вот список хороших советов:
- Храните файл конфигурации по умолчанию в системе управления версиями. Заполните объект конфигурации значениями по умолчанию или импортируйте его в ваших собственных файлах конфигурации перед тем, как заменить значения.
- Воспользуйтесь переменной окружения для переключения между конфигурациями. Это можно сделать вне интерпретатора Python и это позволит упростить разработку и развёртывание, потому что вы можете быстро и легко переключаться между разными конфигурациями, совсем не прикасаясь к коду. Если вы часто работаете над разными проектами, можно создать собственный скрипт, который будет определять текущий каталог проекта, активировать virtualenv и экспортировать конфигурацию режима разработки.
- Используйте инструмент fabric для внесения изменений на сервер эксплуатации и раздельных конфигураций на серверы эксплуатации. За более подробным описанием того, как это сделать, обратитесь к главе fabric-deployment .
Каталоги экземпляров¶
Добавлено в версии 0.8.
Во Flask 0.8 появились каталоги экземпляров. Flask долгое время позволял ссылаться на пути относительно каталога приложения (с помощью Flask.root_path ). Поэтому многие разработчики хранили конфигурацию рядом с приложением. К несчастью, это возможно только если приложение не находится внутри пакета, так как в таком случае root_path указывает внутрь пакета.
Во Flask 0.8 был введён новый атрибут: Flask.instance_path . Он вводит новое понятие, которое называется “каталогом экземпляра”. Каталог экземпляра задуман как каталог, не управляемый системой контроля версий и относящийся к развёрнутому приложению. Это подходящее место для того, чтобы поместить в него файлы, изменяемые в процессе работы или файлы конфигурации.
Можно явным образом указать путь к каталогу экземпляра при создании приложения Flask или можно разрешить Flask’у самому выбрать каталог экземпляра. Чтобы задать его явным образом, воспользуйтесь параметром instance_path :
app = Flask(__name__, instance_path='/path/to/instance/folder')
Помните, что если этот путь указан, он должен быть абсолютным.
Если параметр instance_path не указан, по умолчанию используются следующие места:
-
Не установленный модуль:
/myapp.py /instance
/myapp /__init__.py /instance
$PREFIX/lib/python2.X/site-packages/myapp $PREFIX/var/myapp-instance
Как только стало возможным загружать объект конфигурации из файлов с относительными именами, мы добавили возможность загружать файлы с именами относительно каталога экземпляра. При помощи переключателя instance_relative_config в конструкторе приложения можно указать, должны ли интерпретироваться относительные пути файлов “относительно корня приложения” (по умолчанию) или “относительно каталога экземпляра”:
app = Flask(__name__, instance_relative_config=True)
Ниже представлен полный пример настройки Flask для предварительной загрузки конфигурации из модуля и последующей замены параметров значениями из файла в каталоге конфигурации, если он существует:
app = Flask(__name__, instance_relative_config=True) app.config.from_object('yourapplication.default_settings') app.config.from_pyfile('application.cfg', silent=True)
Путь к каталогу экземпляра может быть найден при помощи Flask.instance_path . Flask также предоставляет более короткий способ открытия файлов из каталога экземпляра при помощи Flask.open_instance_resource() .
Вот пример для обоих способов:
filename = os.path.join(app.instance_path, 'application.cfg') with open(filename) as f: config = f.read() # или при помощи open_instance_resource: with app.open_instance_resource('application.cfg') as f: config = f.read()
Примечания переводчика¶
В качестве перевода для термина cookie было использовано понятие «переменных бразуера».
Информация о флагах httponly и secure взята из статьи HTTP cookie.