Обработка конфигурации
Приложениям необходима некая конфигурация. Есть различные настройки, которые вы можете изменить в зависимости от среды приложения, например, включение режима отладки, установка секретного ключа и другие специфичные для среды вещи.
Способ реализации Flask обычно требует наличия конфигурации при запуске приложения. Вы можете жестко закодировать конфигурацию в коде, что для многих небольших приложений не так уж и плохо, но существуют лучшие способы.
Независимо от того, как вы загружаете свою конфигурацию, доступен объект config, хранящий загруженные значения конфигурации: атрибут config объекта Flask. Здесь Flask сам размещает определённые значения конфигурации, а также расширения могут разместить свои значения конфигурации. Но здесь вы также можете разместить свою собственную конфигурацию.
Основы конфигурации
Атрибут config фактически является подклассом словаря и может быть изменён подобно любому словарю:
app = Flask(__name__) app.config['TESTING'] = True
Определённые значения конфигурации также передаются объекту Flask, так что вы можете читать и записывать их оттуда:
app.testing = True
Для обновления нескольких ключей одновременно можно использовать метод dict.update():
app.config.update(
TESTING=True,
SECRET_KEY='192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
)
Режим отладки
Значение конфигурации DEBUG является специальным, поскольку его поведение может быть непредсказуемым, если его изменить после начала настройки приложения. Для надёжной установки режима отладки используйте опцию --debug в команде flask или flask run. flask run будет использовать интерактивный отладчик и релоадер по умолчанию в режиме отладки.
$ flask --app hello run --debug
Рекомендуется использовать эту опцию. Хотя можно установить DEBUG в вашей конфигурации или коде, это настоятельно не рекомендуется. Его нельзя прочитать до команды flask run, и некоторые системы или расширения могут уже настроить себя на основе предыдущего значения.
Встроенные значения конфигурации
Следующие значения конфигурации используются внутри Flask:
-
DEBUG -
Включен ли режим отладки. При использовании
flask runдля запуска сервера разработки, при возникновении необработанных исключений будет показан интерактивный отладчик, а сервер будет перезагружен при изменениях кода. Атрибутdebugсопоставляется с этим ключом конфигурации. Это устанавливается с помощью переменной окруженияFLASK_DEBUG. Может работать некорректно, если установлено в коде.Не включайте режим отладки при развертывании в рабочей среде.
По умолчанию:
False
-
TESTING -
Включить тестовый режим. Исключения распространяются, а не обрабатываются обработчиками ошибок приложения. Расширения также могут изменить свое поведение для облегчения тестирования. Вы должны включить это в своих тестах.
По умолчанию:
False
-
PROPAGATE_EXCEPTIONS -
Исключения повторно поднимаются, а не обрабатываются обработчиками ошибок приложения. Если не установлено, это неявно истинно, если включен
TESTINGилиDEBUG.По умолчанию:
None
-
TRAP_HTTP_EXCEPTIONS -
Если для исключения типа
HTTPExceptionнет обработчика, повторно поднимите его, чтобы он обрабатывался интерактивным отладчиком, вместо возвращения его в качестве простого ответа об ошибке.По умолчанию:
False
-
TRAP_BAD_REQUEST_ERRORS -
Попытка доступа к ключу, который не существует в словарях запросов, таких как
argsиform, вернёт страницу ошибки 400 Bad Request. Включите это, чтобы обрабатывать ошибку как необработанное исключение, чтобы получить интерактивный отладчик. Это более специфичная версияTRAP_HTTP_EXCEPTIONS. Если не задано, оно включено в режиме отладки.По умолчанию:
None
-
SECRET_KEY -
Секретный ключ, который будет использоваться для безопасного подписывания cookie сессии и может быть использован для любых других задач безопасности расширениями или вашим приложением. Должен быть длинным случайным
bytesилиstr. Например, скопируйте вывод этого в вашу конфигурацию:$ python -c 'import secrets; print(secrets.token_hex())' '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
Не раскрывайте секретный ключ при публикации вопросов или коммитах кода.
По умолчанию:
None
-
SESSION_COOKIE_NAME -
Имя cookie сессии. Можно изменить, если у вас уже есть cookie с таким же именем.
По умолчанию:
'session'
-
SESSION_COOKIE_DOMAIN -
Значение параметра
Domainдля cookie сессии. Если не установлено, браузеры будут отправлять cookie только на точный домен, из которого он был установлен. В противном случае они будут отправлять его и на любые поддомены заданного значения.Не установление этого значения более ограниченно и безопасно, чем его установка.
По умолчанию:
NoneИзменено в версии 2.3: Не установлено по умолчанию, не использует
SERVER_NAMEпо умолчанию.
-
SESSION_COOKIE_PATH -
Путь, для которого будет действительна cookie сессии. Если не установлено, cookie будет действителен в рамках
APPLICATION_ROOTили/, если это не задано.По умолчанию:
None
-
SESSION_COOKIE_HTTPONLY -
Браузеры не позволят JavaScript получить доступ к cookie, помеченным как «только HTTP», для обеспечения безопасности.
По умолчанию:
True
-
SESSION_COOKIE_SECURE -
Браузеры будут отправлять cookie только с запросами по протоколу HTTPS, если для cookie установлено значение «secure». Приложение должно обслуживаться через HTTPS, для того, чтобы это имело смысл.
По умолчанию:
False
-
SESSION_COOKIE_SAMESITE -
Ограничьте то, как cookie отправляются с запросами с внешних сайтов. Можно установить на
'Lax'(рекомендуется) или'Strict'. См. Параметры Set-Cookie.По умолчанию:
NoneЖурнал изменений
Введено в версии 1.0.
-
PERMANENT_SESSION_LIFETIME -
Если
session.permanentравно true, срок действия cookie будет установлен на это количество секунд в будущем. Может быть либоdatetime.timedelta, либоint.Реализация cookie по умолчанию Flask проверяет, что криптографическая подпись не старше этого значения.
По умолчанию:
timedelta(days=31)(2678400секунд)
-
SESSION_REFRESH_EACH_REQUEST -
Управление отправкой cookie с каждым ответом, когда
session.permanentравно true. Отправка cookie каждый раз (по умолчанию) может более надёжно предотвратить истечение сессии, но использует больше пропускной способности. На не постоянные сессии это не влияет.По умолчанию:
True
-
USE_X_SENDFILE -
При передаче файлов установить заголовок
X-Sendfileвместо передачи данных с Flask. Некоторые веб-серверы, такие как Apache, распознают это и передают данные более эффективно. Это имеет смысл только при использовании такого сервера.По умолчанию:
False
-
SEND_FILE_MAX_AGE_DEFAULT -
При передаче файлов установить максимальную продолжительность кеширования на это количество секунд. Может быть
datetime.timedeltaилиint. Переопределите это значение для каждого файла с помощьюget_send_file_max_age()в приложении или модуле.Если
None,send_fileуказывает браузеру использовать условные запросы вместо кэширования по времени, что обычно предпочтительнее.По умолчанию:
None
-
SERVER_NAME -
Сообщить приложению о том, к какому хосту и порту оно привязано. Необходимо для поддержки сопоставления маршрутов по поддоменам.
Если установлено,
url_forможет генерировать внешние URL-адреса только с контекстом приложения вместо контекста запроса.По умолчанию:
NoneИзменено в версии 2.3: Не влияет на
SESSION_COOKIE_DOMAIN.
-
APPLICATION_ROOT -
Указать приложению путь, под которым оно смонтировано приложением/веб-сервером. Это используется для генерации URL-адресов за пределами контекста запроса (внутри запроса, диспетчер отвечает за установку
SCRIPT_NAMEвместо этого; см. Перенаправление приложения для примеров конфигурации перенаправления).Будет использоваться для пути cookie сессии, если
SESSION_COOKIE_PATHне задан.По умолчанию:
'/'
-
PREFERRED_URL_SCHEME -
Используйте эту схему для генерации внешних URL-адресов, когда нет контекста запроса.
По умолчанию:
'http'
-
MAX_CONTENT_LENGTH -
Не читать больше этого количества байтов из входящих данных запроса. Если не задано и запрос не указывает
CONTENT_LENGTH, данные не будут читаться по соображениям безопасности.По умолчанию:
None
-
TEMPLATES_AUTO_RELOAD -
Перезагружать шаблоны при их изменении. Если не задано, оно будет включено в режиме отладки.
По умолчанию:
None
-
EXPLAIN_TEMPLATE_LOADING -
Вести журнал отладочной информации, отслеживающей, как был загружен файл шаблона. Это может быть полезно, чтобы понять, почему шаблон не был загружен или загружен неверный файл.
По умолчанию:
False
-
MAX_COOKIE_SIZE -
Вывести предупреждение, если заголовки cookie превышают это количество байт. По умолчанию
4093. Большие cookie могут быть проигнорированы браузерами. Установите0для отключения предупреждения.
Изменено в версии 2.3: JSON_AS_ASCII, JSON_SORT_KEYS, JSONIFY_MIMETYPE, и JSONIFY_PRETTYPRINT_REGULAR были удалены. У поставщика app.json по умолчанию вместо этого есть эквивалентные атрибуты.
Изменено в версии 2.3: ENV был удален.
Журнал изменений
Изменено в версии 2.2: Удалено PRESERVE_CONTEXT_ON_EXCEPTION.
Изменено в версии 1.0: LOGGER_NAME и LOGGER_HANDLER_POLICY были удалены. См. Ведение журнала для получения информации о конфигурации.
Добавлен ENV, чтобы отразить переменную среды FLASK_ENV.
Добавлен SESSION_COOKIE_SAMESITE, чтобы управлять параметром SameSite куки сессии.
Добавлен MAX_COOKIE_SIZE, чтобы управлять предупреждением из Werkzeug.
Новое в версии 0.11: SESSION_REFRESH_EACH_REQUEST, TEMPLATES_AUTO_RELOAD, LOGGER_HANDLER_POLICY, EXPLAIN_TEMPLATE_LOADING
Новое в версии 0.10: JSON_AS_ASCII, JSON_SORT_KEYS, JSONIFY_PRETTYPRINT_REGULAR
Новое в версии 0.9: PREFERRED_URL_SCHEME
Новое в версии 0.8: TRAP_BAD_REQUEST_ERRORS, TRAP_HTTP_EXCEPTIONS, APPLICATION_ROOT, SESSION_COOKIE_DOMAIN, SESSION_COOKIE_PATH, SESSION_COOKIE_HTTPONLY, SESSION_COOKIE_SECURE
Новое в версии 0.7: PROPAGATE_EXCEPTIONS, PRESERVE_CONTEXT_ON_EXCEPTION
Новое в версии 0.6: MAX_CONTENT_LENGTH
Новое в версии 0.5: SERVER_NAME
Новое в версии 0.4: LOGGER_NAME
Настройка из файлов Python
Конфигурация становится более полезной, если её можно хранить в отдельном файле, предпочтительно вне пакета приложения. Вы можете развернуть приложение, затем отдельно настроить его для конкретного развертывания.
Типичный шаблон:
app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')
Этот код сначала загружает конфигурацию из модуля yourapplication.default_settings, а затем перезаписывает значения содержимым файла, на который указывает переменная среды YOURAPPLICATION_SETTINGS. Эта переменная среды может быть задана в командной строке перед запуском сервера:
$ export YOURAPPLICATION_SETTINGS=/path/to/settings.cfg $ flask run * Running on http://127.0.0.1:5000/
$ set -x YOURAPPLICATION_SETTINGS /path/to/settings.cfg $ flask run * Running on http://127.0.0.1:5000/
> set YOURAPPLICATION_SETTINGS=\path\to\settings.cfg > flask run * Running on http://127.0.0.1:5000/
> $env:YOURAPPLICATION_SETTINGS = "\path\to\settings.cfg" > flask run * Running on http://127.0.0.1:5000/
Файлы конфигурации — это обычные файлы Python. Только значения, написанные заглавными буквами, фактически сохраняются в объекте конфигурации. Поэтому убедитесь, что используете заглавные буквы для ключей конфигурации.
Вот пример файла конфигурации:
# Example configuration SECRET_KEY = '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
Убедитесь, что конфигурация загружается очень рано, чтобы расширения могли получить доступ к конфигурации при запуске. В объекте конфигурации также есть другие методы для загрузки из отдельных файлов. Для получения полной справки, прочитайте документацию по объекту Config.
Настройка из файлов данных
Также можно загрузить конфигурацию из файла в формате по вашему выбору, используя from_file(). Например, для загрузки из файла TOML:
import tomllib
app.config.from_file("config.toml", load=tomllib.load, text=False)
Или из файла JSON:
import json
app.config.from_file("config.json", load=json.load)
Настройка из переменных среды
Помимо указания на файлы конфигурации с помощью переменных среды, вы можете найти полезным (или необходимым) управлять значениями конфигурации непосредственно из среды. Flask может быть настроен на загрузку всех переменных среды, начинающихся со специфического префикса, в конфигурацию, используя from_prefixed_env().
Переменные среды могут быть заданы в командной строке перед запуском сервера:
$ export FLASK_SECRET_KEY="5f352379324c22463451387a0aec5d2f" $ export FLASK_MAIL_ENABLED=false $ flask run * Running on http://127.0.0.1:5000/
$ set -x FLASK_SECRET_KEY "5f352379324c22463451387a0aec5d2f" $ set -x FLASK_MAIL_ENABLED false $ flask run * Running on http://127.0.0.1:5000/
> set FLASK_SECRET_KEY="5f352379324c22463451387a0aec5d2f" > set FLASK_MAIL_ENABLED=false > flask run * Running on http://127.0.0.1:5000/
> $env:FLASK_SECRET_KEY = "5f352379324c22463451387a0aec5d2f" > $env:FLASK_MAIL_ENABLED = "false" > flask run * Running on http://127.0.0.1:5000/
Переменные затем можно загрузить и получить доступ к ним через конфигурацию с ключом, равным имени переменной среды без префикса, т.е.
app.config.from_prefixed_env() app.config["SECRET_KEY"] # Is "5f352379324c22463451387a0aec5d2f"
Префикс по умолчанию — FLASK_. Это настраивается через аргумент prefix метода from_prefixed_env().
Значения будут парситься для попытки конвертации в тип более специфичный, чем строки. По умолчанию используется json.loads(), поэтому возможны любые допустимые значения JSON, включая списки и словари. Это настраивается через аргумент loads метода from_prefixed_env().
При добавлении булевого значения с парсингом по умолчанию JSON, только «true» и «false», в нижнем регистре, являются допустимыми значениями. Имейте в виду, что любая непустая строка считается True в Python.
Возможна установка ключей вложенных словарей, разделяя ключи двойным подчёркиванием (__). Любые промежуточные ключи, которые не существуют в родительском словаре, будут инициализированы пустым словарем.
$ export FLASK_MYAPI__credentials__username=user123
app.config["MYAPI"]["credentials"]["username"] # Is "user123"
В Windows ключи переменных среды всегда заглавные, поэтому вышеприведённый пример в итоге станет MYAPI__CREDENTIALS__USERNAME.
Для ещё более продвинутых возможностей загрузки конфигурации, включая слияние и регистронезависимую поддержку Windows, попробуйте специализированную библиотеку, такую как Dynaconf, которая включает интеграцию с Flask.
Рекомендации по настройке
Недостатком ранее упомянутого подхода является то, что тестирование становится немного сложнее. Нет единого 100%-го решения для этой проблемы в общем случае, но есть несколько моментов, которые вы можете учитывать, чтобы улучшить этот опыт:
- Создавайте своё приложение в функции и регистрируйте голубые печати в нём. Таким образом, вы можете создавать несколько экземпляров приложения с различными привязанными конфигурациями, что значительно упрощает тестирование. Вы можете использовать это для передачи конфигурации по мере необходимости.
- Не пишите код, которому нужна конфигурация во время импорта. Если ограничиться доступом к конфигурации только во время запроса, вы можете перенастраивать объект по мере необходимости.
- Убедитесь, что конфигурация загружается очень рано, чтобы расширения могли получить доступ к конфигурации при вызове
init_app.
Разработка / Производство
Большинству приложений требуется более одной конфигурации. Должны быть, по крайней мере, отдельные конфигурации для сервера производства и для сервера, используемого во время разработки. Наиболее простой способ справиться с этим — использовать стандартную конфигурацию, которая всегда загружается и является частью системы контроля версий, и отдельную конфигурацию, которая переопределяет значения по мере необходимости, как указано в примере выше:
app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')
Затем вам просто нужно добавить отдельный config.py файл и экспортировать YOURAPPLICATION_SETTINGS=/path/to/config.py, и всё готово. Однако существуют и альтернативные способы. Например, вы можете использовать импорты или наследование.
В мире Django очень популярен метод явного импорта в файле конфигурации, добавив from yourapplication.default_settings
import * в начало файла, а затем вручную переопределяя изменения. Вы также можете проанализировать переменную окружения, например, YOURAPPLICATION_MODE, и установить её значение в production, development и т.д., а затем импортировать разные жёстко закодированные файлы, основываясь на этом значении.
Интересным шаблоном является также использование классов и наследования для конфигурации:
class Config(object):
TESTING = False
class ProductionConfig(Config):
DATABASE_URI = 'mysql://user@localhost/foo'
class DevelopmentConfig(Config):
DATABASE_URI = "sqlite:////tmp/foo.db"
class TestingConfig(Config):
DATABASE_URI = 'sqlite:///:memory:'
TESTING = True
Для активации такой конфигурации вам нужно только вызвать from_object():
app.config.from_object('configmodule.ProductionConfig')
Обратите внимание, что from_object() не создаёт объект класса. Если вам нужно создать объект класса, например, для доступа к свойству, то это необходимо сделать до вызова from_object():
from configmodule import ProductionConfig
app.config.from_object(ProductionConfig())
# Alternatively, import via string:
from werkzeug.utils import import_string
cfg = import_string('configmodule.ProductionConfig')()
app.config.from_object(cfg)
Создание объекта конфигурации позволяет вам использовать @property в ваших классах конфигурации:
class Config(object):
"""Base config, uses staging database server."""
TESTING = False
DB_SERVER = '192.168.1.56'
@property
def DATABASE_URI(self): # Note: all caps
return f"mysql://user@{self.DB_SERVER}/foo"
class ProductionConfig(Config):
"""Uses production database server."""
DB_SERVER = '192.168.19.32'
class DevelopmentConfig(Config):
DB_SERVER = 'localhost'
class TestingConfig(Config):
DB_SERVER = 'localhost'
DATABASE_URI = 'sqlite:///:memory:'
Существует множество разных способов, и как вы хотите управлять своими файлами конфигурации — решать вам. Однако вот список полезных рекомендаций:
- Храните стандартную конфигурацию в системе контроля версий. Или заполните конфигурацию этой стандартной конфигурацией, или импортируйте её в свои собственные файлы конфигурации перед переопределением значений.
- Используйте переменную окружения для переключения между конфигурациями. Это можно сделать вне интерпретатора Python, что значительно упрощает разработку и развертывание, поскольку вы можете быстро и легко переключаться между различными конфигурациями, не изменяя код. Если вы часто работаете над разными проектами, вы можете даже создать свой скрипт для импорта, который активирует виртуальную среду и экспортирует для вас конфигурацию разработки.
- Используйте инструмент, такой как fabric, для отправки кода и конфигурации на серверы производства по отдельности.
Папки примеров
Журнал изменений
Новое в версии 0.8.
Flask 0.8 вводит папки примеров. Flask долгое время позволял ссылаться на пути, относительные к папке приложения напрямую (через Flask.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/pythonX.Y/site-packages/myapp $PREFIX/var/myapp-instance
$PREFIX— префикс вашей установки Python. Это может быть/usrили путь к вашей виртуальной среде. Вы можете вывести значениеsys.prefixдля просмотра установленного префикса.
Поскольку объект конфигурации обеспечивал загрузку файлов конфигурации из относительных имён файлов, мы сделали возможным изменение загрузки, используя имена файлов, относящиеся к пути примера, если это необходимо. Поведение относительных путей в файлах конфигурации может быть переключено между «относительно корневого каталога приложения» (по умолчанию) и «относительно папки примера» с помощью переключателя 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()
# or via open_instance_resource:
with app.open_instance_resource('application.cfg') as f:
config = f.read()
© 2007–2022 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.3.x/config/