Обработка конфигурации
Приложениям необходима некая конфигурация. Существуют различные настройки, которые вы можете изменить в зависимости от среды приложения, например, включение режима отладки, установка секретного ключа и другие специфичные для среды вещи.
Дизайн Flask обычно требует, чтобы конфигурация была доступна при запуске приложения. Вы можете жестко закодировать конфигурацию в коде, что для многих небольших приложений не так уж и плохо, но существуют лучшие способы.
Независимо от того, как вы загружаете свою конфигурацию, доступен объект конфигурации, который хранит загруженные значения конфигурации: атрибут config объекта Flask. Именно сюда Flask помещает определенные значения конфигурации, а также расширения могут помещать свои значения конфигурации. Но здесь вы также можете хранить свою собственную конфигурацию.
Основные принципы конфигурации
Атрибут config фактически является подклассом словаря и может быть изменён так же, как и любой словарь:
app = Flask(__name__) app.config['TESTING'] = True
Определённые значения конфигурации также передаются объекту Flask, так что вы можете читать и записывать их оттуда:
app.testing = True
Для обновления нескольких ключей одновременно можно использовать метод dict.update():
app.config.update(
TESTING=True,
SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/'
)
Среда и функции отладки
Значения конфигурации ENV и DEBUG являются особыми, потому что их изменение после начала настройки приложения может привести к непредсказуемым результатам. Для надёжной установки режима среды и отладки Flask использует переменные окружения.
Среда используется для указания Flask, расширениям и другим программам, таким как Sentry, в какой среде работает Flask. Она контролируется переменной окружения FLASK_ENV и по умолчанию установлена в production.
Установка FLASK_ENV в development включит режим отладки. flask run будет по умолчанию использовать интерактивный отладчик и перезагрузчик в режиме отладки. Чтобы управлять этим отдельно от среды, используйте флаг FLASK_DEBUG.
Журнал изменений
Изменено в версии 1.0: Добавлена возможность управления средой отдельно от режима отладки. Среда разработки включает режим отладки.
Для переключения Flask на среду разработки и включения режима отладки установите FLASK_ENV:
$ export FLASK_ENV=development $ flask run
> set FLASK_ENV=development > flask run
> $env:FLASK_ENV = "development" > flask run
Рекомендуется использование переменных среды, как описано выше. Хотя можно установить ENV и DEBUG в вашей конфигурации или коде, это настоятельно не рекомендуется. Они не могут быть прочитаны командой flask на ранней стадии, и некоторые системы или расширения могут быть уже настроены на основе предыдущего значения.
Встроенные значения конфигурации
Следующие значения конфигурации используются внутри Flask:
-
ENV -
В какой среде запущено приложение. Flask и расширения могут включать поведение, основанное на среде, например, включение режима отладки. Атрибут
envсоответствует этому ключу конфигурации. Он устанавливается переменной окруженияFLASK_ENVи может вести себя непредсказуемо, если установлен в коде.Не включайте режим разработки при развертывании в производстве.
По умолчанию:
'production'Журнал изменений
Новое в версии 1.0.
-
DEBUG -
Включен ли режим отладки. При использовании
flask runдля запуска сервера разработки будет показан интерактивный отладчик для необработанных исключений, и сервер будет перезагружен при изменениях кода. Атрибутdebugсоответствует этому ключу конфигурации. Он включен, когдаENVравен'development', и переопределяется переменной окруженияFLASK_DEBUG. Он может вести себя непредсказуемо, если установлен в коде.Не включайте режим отладки при развертывании в производстве.
По умолчанию:
TrueеслиENVравно'development', илиFalseв противном случае.
-
TESTING -
Включить режим тестирования. Исключения распространяются, а не обрабатываются обработчиками ошибок приложения. Расширения также могут изменить свое поведение для облегчения тестирования. Вы должны включить это в своих тестах.
По умолчанию:
False
-
PROPAGATE_EXCEPTIONS -
Исключения повторно поднимаются, а не обрабатываются обработчиками ошибок приложения. Если не установлено, это подразумевается, если
TESTINGилиDEBUGвключены.По умолчанию:
None
-
PRESERVE_CONTEXT_ON_EXCEPTION -
Не удалять контекст запроса при возникновении исключения. Если не установлено, это верно, если
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 os; print(os.urandom(16))' b'_5#y2L"F4Q8z\n\xec]/'
Не раскрывайте секретный ключ при публикации вопросов или коммитах кода.
По умолчанию:
None
-
SESSION_COOKIE_NAME -
Название cookie сессии. Может быть изменено, если у вас уже есть cookie с таким же именем.
По умолчанию:
'session'
-
SESSION_COOKIE_DOMAIN -
Правило соответствия домена, для которого cookie сессии будет действительным. Если не указано, cookie будет действительным для всех поддоменов
SERVER_NAME. ЕслиFalse, домен cookie не будет установлен.По умолчанию:
None
-
SESSION_COOKIE_PATH -
Путь, для которого cookie сессии будет действительным. Если не указано, cookie будет действительным под
APPLICATION_ROOTили/если это не установлено.По умолчанию:
None
-
SESSION_COOKIE_HTTPONLY -
Браузеры не позволят JavaScript получить доступ к cookie, помеченным как «только HTTP», для обеспечения безопасности.
По умолчанию:
True
-
SESSION_COOKIE_SECURE -
Браузеры будут отправлять cookie только с запросами по HTTPS, если cookie помечен как «защищенный». Приложение должно быть доступно по 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 -
Информирует приложение о том, к какому хосту и порту оно привязано. Требуется для поддержки сопоставления маршрутов для поддоменов.
Если установлено, будет использоваться для домена cookie сессии, если
SESSION_COOKIE_DOMAINне установлено. Современные веб-браузеры не позволят устанавливать cookie для доменов без точки. Чтобы использовать домен локально, добавьте все имена, которые должны маршрутизироваться к приложению, в свой файлhosts.127.0.0.1 localhost.dev
Если установлено,
url_forможет генерировать внешние URL-адреса только с контекстом приложения, а не с контекстом запроса.По умолчанию:
None
-
APPLICATION_ROOT -
Информирует приложение о том, под каким путём оно смонтировано приложением/веб-сервером. Используется для генерации URL-адресов за пределами контекста запроса (внутри запроса, диспетчер отвечает за установку
SCRIPT_NAMEвместо; см. Обработка приложений для примеров конфигурации диспетчера).Будет использоваться для пути cookie сессии, если
SESSION_COOKIE_PATHне установлено.По умолчанию:
'/'
-
PREFERRED_URL_SCHEME -
Использовать этот протокол для генерации внешних URL-адресов при отсутствии контекста запроса.
По умолчанию:
'http'
-
MAX_CONTENT_LENGTH -
Не читать более этого количества байтов из входящих данных запроса. Если не установлено и запрос не указывает
CONTENT_LENGTH, данные не будут считываться для обеспечения безопасности.По умолчанию:
None
-
JSON_AS_ASCII -
Сериализовать объекты в JSON с кодировкой ASCII. Если отключено, возвращаемый JSON из
jsonifyбудет содержать символы Unicode. Это имеет последствия для безопасности при рендеринге JSON в JavaScript в шаблонах и, как правило, должно оставаться включённым.По умолчанию:
True
-
JSON_SORT_KEYS -
Сортировать ключи объектов JSON в алфавитном порядке. Это полезно для кэширования, так как гарантирует, что данные сериализуются одинаково независимо от начального значения генератора случайных чисел Python. Хотя не рекомендуется, вы можете отключить это для возможного повышения производительности ценой кэширования.
По умолчанию:
True
-
JSONIFY_PRETTYPRINT_REGULAR -
Ответы
jsonifyбудут выводиться с новой строкой, пробелами и отступами для лучшей читаемости человеком. Всегда включено в режиме отладки.По умолчанию:
False
-
JSONIFY_MIMETYPE -
MIME-тип ответов
jsonify.По умолчанию:
'application/json'
-
TEMPLATES_AUTO_RELOAD -
Перезагружать шаблоны при их изменении. Если не установлено, будет включено в режиме отладки.
По умолчанию:
None
-
EXPLAIN_TEMPLATE_LOADING -
Записывать отладочную информацию, отслеживая, как загружался файл шаблона. Это может быть полезно для выяснения причин, по которым шаблон не загрузился или загрузился не тот файл.
По умолчанию:
False
-
MAX_COOKIE_SIZE -
Выводить предупреждение, если заголовки cookie превышают это количество байтов. По умолчанию
4093. Более крупные cookie могут быть проигнорированы браузерами. Установите значение0для отключения предупреждения.
Changelog
Изменено в версии 1.0: LOGGER_NAME и LOGGER_HANDLER_POLICY были удалены. См. Ведение журнала для информации о конфигурации.
Добавлен ENV для отражения переменной среды FLASK_ENV.
Добавлен SESSION_COOKIE_SAMESITE для управления параметром SameSite cookie сессии.
Добавлен 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
Конфигурация становится более полезной, если вы можете хранить её в отдельном файле, предпочтительно вне самого пакета приложения. Это позволяет упаковывать и распространять приложение с помощью различных инструментов обработки пакетов (Развёртывание с помощью Setuptools) и впоследствии изменять файл конфигурации.
Поэтому распространённым шаблоном является следующий:
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 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. Только значения с заглавными буквами фактически хранятся в объекте config позднее. Поэтому убедитесь, что используете заглавные буквы для своих ключей конфигурации.
Вот пример файла конфигурации:
# Example configuration SECRET_KEY = b'_5#y2L"F4Q8z\n\xec]/'
Убедитесь, что конфигурация загружается очень рано, чтобы расширения могли получить к ней доступ при запуске. В объекте config также есть другие методы для загрузки из отдельных файлов. Для полного справочника прочитайте документацию по объекту Config.
Конфигурирование из файлов данных
Также можно загрузить конфигурацию из файла в формате по вашему выбору, используя from_file(). Например, для загрузки из файла TOML:
import toml
app.config.from_file("config.toml", load=toml.load)
Или из файла JSON:
import json
app.config.from_file("config.json", load=json.load)
Настройка из переменных окружения
В дополнение к указанию на файлы конфигурации с помощью переменных окружения, вы можете найти полезным (или необходимым) контролировать значения конфигурации непосредственно из окружения.
Переменные окружения могут быть установлены в оболочке перед запуском сервера:
$ export SECRET_KEY="5f352379324c22463451387a0aec5d2f" $ export MAIL_ENABLED=false $ flask run * Running on http://127.0.0.1:5000/
> set SECRET_KEY="5f352379324c22463451387a0aec5d2f" > set MAIL_ENABLED=false > flask run * Running on http://127.0.0.1:5000/
> $env:SECRET_KEY = "5f352379324c22463451387a0aec5d2f" > $env:MAIL_ENABLED = "false" > flask run * Running on http://127.0.0.1:5000/
Хотя этот подход прост в использовании, важно помнить, что переменные окружения являются строками — они не десериализуются автоматически в типы Python.
Вот пример файла конфигурации, который использует переменные окружения:
import os
_mail_enabled = os.environ.get("MAIL_ENABLED", default="true")
MAIL_ENABLED = _mail_enabled.lower() in {"1", "t", "true"}
SECRET_KEY = os.environ.get("SECRET_KEY")
if not SECRET_KEY:
raise ValueError("No SECRET_KEY set for Flask application")
Обратите внимание, что любое значение, кроме пустой строки, будет интерпретироваться как булево True значение в Python, что требует осторожности, если среда явно устанавливает значения, предназначенные для False.
Убедитесь, что конфигурация загружается очень рано, чтобы расширения могли получить доступ к конфигурации при запуске. Также есть другие методы объекта config для загрузки из отдельных файлов. Для полной справки, прочитайте документацию класса Config.
Рекомендации по настройке
Недостатком упомянутого подхода является то, что тестирование становится немного сложнее. Нет единого 100% решения для этой проблемы в общем случае, но есть несколько моментов, которые можно учитывать для улучшения этого опыта:
- Создайте приложение в функции и зарегистрируйте шаблоны на нём. Таким образом, вы можете создавать несколько экземпляров вашего приложения с разными прикреплёнными конфигурациями, что значительно упрощает тестирование. Вы можете использовать это для передачи конфигурации по мере необходимости.
- Не пишите код, которому требуется конфигурация во время импорта. Если вы ограничитесь доступом к конфигурации только при запросе, вы сможете переконфигурировать объект позже по мере необходимости.
Разработка / Производство
Большинству приложений требуется более одной конфигурации. Должны быть, по крайней мере, отдельные конфигурации для сервера производства и используемой во время разработки. Наиболее простой способ справиться с этим — использовать стандартную конфигурацию, которая всегда загружается и является частью контроля версий, и отдельную конфигурацию, которая переопределяет значения по необходимости, как указано в примере выше:
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, в производственной среде, чтобы отдельно распространять код и конфигурации на серверы производства. Для некоторых подробностей о том, как это сделать, перейдите к паттерну Развёртывание с Fabric.
Папки экземпляров
Changelog
В версии 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, чтобы увидеть, чему установлено значение префикса.
Поскольку объект config обеспечивал загрузку файлов конфигурации из относительных имён файлов, мы сделали возможным изменение загрузки через имена файлов, чтобы они были относительными к пути экземпляра, если это необходимо. Поведение относительных путей в файлах конфигурации может быть изменено с «относительно корня приложения» (значение по умолчанию) на «относительно папки экземпляра» с помощью переключателя 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–2021 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.0.x/config/