Обработка конфигурации

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

Способ разработки 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:

ENV

В какой среде работает приложение. Атрибут env сопоставляется с этим ключом конфигурации.

По умолчанию: 'production'

Не рекомендуется, начиная с версии 2.2: Будет удалена в версии Flask 2.3. Вместо этого используйте --debug.

Changelog

Добавлено в версии 1.0.

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. Например, скопируйте этот вывод в свой config:

$ python -c 'import secrets; print(secrets.token_hex())'
'192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'

Не раскрывайте секретный ключ при размещении вопросов или совершении кода..

По умолчанию: None

Имя сессионного файла cookie. Может быть изменено в случае, если у вас уже есть cookie с таким же именем.

По умолчанию: 'session'

Правило соответствия домена, для которого будет действовать сессионный файл cookie. Если не задано, cookie будет действителен для всех поддоменов SERVER_NAME. Если False, домен cookie не будет установлен.

По умолчанию: None

Путь, по которому будет действовать сессионный файл cookie. Если не задан, cookie будет действителен для пути APPLICATION_ROOT или /, если он не задан.

По умолчанию: None

В целях безопасности браузеры не разрешают JavaScript доступ к файлам cookie, помеченным как «только HTTP».

По умолчанию: True

Браузеры будут отправлять куки с запросами через HTTPS, только если куки помечены как «безопасные». Чтобы это имело смысл, приложение должно обслуживаться через HTTPS.

По умолчанию: False

Ограничивает отправку файлов cookie при запросах с внешних сайтов. Может быть установлено значение 'Lax' (рекомендуется) или 'Strict'. См. Опции Set-Cookie.

По умолчанию: None

Changelog

Добавлено в версии 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 не установлен. Современные веб-браузеры не позволяют устанавливать cookies для доменов без точки. Чтобы использовать домен локально, добавьте в файл 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

Сериализация объектов в ASCII-кодированный JSON. Если эта функция отключена, JSON, возвращаемый из jsonify, будет содержать символы Unicode. Это имеет последствия для безопасности при преобразовании JSON в JavaScript в шаблонах, и обычно должно оставаться включенным.

По умолчанию: True

Не рекомендуется, начиная с версии 2.2: Будет удалена в версии Flask 2.3. Вместо этого установите app.json.ensure_ascii.

JSON_SORT_KEYS

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

По умолчанию: True

Не рекомендуется, начиная с версии 2.2: Будет удалена в версии Flask 2.3. Вместо этого установите app.json.sort_keys.

JSONIFY_PRETTYPRINT_REGULAR

jsonify() ответы будут выводиться с новыми строками, пробелами и отступами для более удобного чтения человеком. Всегда включается в режиме отладки.

По умолчанию: False

Не рекомендуется, начиная с версии 2.2: Будет удалена в версии Flask 2.3. Вместо этого установите app.json.compact.

JSONIFY_MIMETYPE

Mimetype ответов jsonify.

По умолчанию: 'application/json'

Не рекомендуется, начиная с версии 2.2: Будет удалена в версии Flask 2.3. Вместо этого установите app.json.mimetype.

TEMPLATES_AUTO_RELOAD

Перезагружать шаблоны при их изменении. Если не установлен, то будет включен в режиме отладки.

По умолчанию: None

EXPLAIN_TEMPLATE_LOADING

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

По умолчанию: False

Предупреждать, если размер заголовков cookie превышает указанное количество байт. По умолчанию установлено значение 4093. Файлы cookie большего размера могут молча игнорироваться браузерами. Установите значение 0, чтобы отключить предупреждение.

Изменено в версии 2.2: Удалено PRESERVE_CONTEXT_ON_EXCEPTION.

Изменено в версии 2.2: JSON_AS_ASCII, JSON_SORT_KEYS, JSONIFY_MIMETYPE и JSONIFY_PRETTYPRINT_REGULAR будут удалены во Flask 2.3. Вместо них эквивалентные атрибуты есть у провайдера по умолчанию app.json.

Изменено в версии 2.2: ENV будет удален в версии Flask 2.3. Вместо этого используйте --debug.

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

Конфигурация становится более полезной, если вы можете хранить ее в отдельном файле, в идеале расположенном вне пакета приложения. Вы можете развернуть приложение, а затем отдельно сконфигурировать его для конкретного развертывания.

Общая картина такова:

app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')

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

Bash

$ 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/

CMD

> set YOURAPPLICATION_SETTINGS=\path\to\settings.cfg
> flask run
 * Running on http://127.0.0.1:5000/

Powershell

> $env:YOURAPPLICATION_SETTINGS = "\path\to\settings.cfg"
> flask run
 * Running on http://127.0.0.1:5000/

Сами файлы конфигурации являются фактическими файлами Python. В дальнейшем в объекте config будут храниться только значения в верхнем регистре. Поэтому обязательно используйте заглавные буквы для ключей конфигурации.

Вот пример конфигурационного файла:

# Example configuration
SECRET_KEY = '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'

Обязательно загрузите конфигурацию на самом раннем этапе, чтобы расширения имели возможность доступа к ней при запуске. Существуют и другие методы объекта 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)

Настройка с помощью переменных среды

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

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

Bash

$ 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/

CMD

> set FLASK_SECRET_KEY="5f352379324c22463451387a0aec5d2f"
> set FLASK_MAIL_ENABLED=false
> flask run
 * Running on http://127.0.0.1:5000/

Powershell

> $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% решения этой проблемы в целом, но есть несколько вещей, которые можно иметь в виду, чтобы улучшить этот опыт:

  1. Создайте свое приложение в функции и зарегистрируйте на нем чертежи. Таким образом, вы можете создать несколько экземпляров приложения с разными конфигурациями, что значительно упрощает модульное тестирование. Вы можете использовать это для передачи конфигурации по мере необходимости.

  2. Не пишите код, которому нужна конфигурация во время импорта. Если вы ограничитесь доступом к конфигурации только по запросу, вы сможете переконфигурировать объект позже по мере необходимости.

  3. Обязательно загрузите конфигурацию на самом раннем этапе, чтобы расширения могли получить доступ к ней при вызове 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 и значительно упрощает разработку и развертывание, поскольку вы можете быстро и легко переключаться между различными конфигурациями, не касаясь кода. Если вы часто работаете над разными проектами, вы даже можете создать свой собственный скрипт для сорсинга, который активирует virtualenv и экспортирует конфигурацию разработки для вас.

  • Используйте такой инструмент, как 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 или путь к вашему virtualenv. Вы можете вывести значение 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()
Вернуться на верх