• en
  • Language: ru
  • Documentation version: 1.1.x

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

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

Способ разработки 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=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_ENV для управления средой отдельно от режима отладки. Среда разработки включает режим отладки.

Чтобы переключить Flask в среду разработки и включить режим отладки, установите FLASK_ENV:

$ export FLASK_ENV=development
$ flask run

(В Windows используйте set вместо export).

Рекомендуется использовать переменные окружения, как описано выше. Хотя можно установить 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 и может быть использован для любых других нужд, связанных с безопасностью, расширениями или вашим приложением. Это должна быть длинная случайная строка байтов, хотя юникод тоже принимается. Например, скопируйте этот вывод в свой config:

$ python -c 'import os; print(os.urandom(16))'
b'_5#y2L"F4Q8z\n\xec]/'

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

По умолчанию: 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

Добавлено в версии 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() в приложении или чертеже.

По умолчанию: timedelta(hours=12) (43200 секунд)

SERVER_NAME

Сообщает приложению, к какому хосту и порту оно привязано. Требуется для поддержки поддоменного согласования маршрутов.

Если установлен, то будет использоваться для домена cookie сессии, если SESSION_COOKIE_DOMAIN не установлен. Современные веб-браузеры не позволяют устанавливать cookie для доменов без точки. Чтобы использовать домен локально, добавьте в файл hosts все имена, которые должны направляться к приложению.

127.0.0.1 localhost.dev

Если установлено, url_for может генерировать внешние URL, используя только контекст приложения вместо контекста запроса.

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

APPLICATION_ROOT

Сообщает приложению, по какому пути оно смонтировано приложением / веб-сервером. Это используется для генерации URL вне контекста запроса (внутри запроса диспетчер отвечает за установку SCRIPT_NAME вместо этого; примеры конфигурации диспетчера см. в Application Dispatching).

Будет использоваться для пути к cookie сессии, если SESSION_COOKIE_PATH не установлен.

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

PREFERRED_URL_SCHEME

Используйте эту схему для генерации внешних URL-адресов, когда они не находятся в контексте запроса.

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

MAX_CONTENT_LENGTH

Не считывать больше этого количества байт из входящих данных запроса. Если не установлено и в запросе не указано CONTENT_LENGTH, данные не будут считываться для безопасности.

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

JSON_AS_ASCII

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

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

JSON_SORT_KEYS

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

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

JSONIFY_PRETTYPRINT_REGULAR

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

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

JSONIFY_MIMETYPE

Тип mimetype ответов jsonify.

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

TEMPLATES_AUTO_RELOAD

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

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

EXPLAIN_TEMPLATE_LOADING

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

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

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

Добавлено в версии 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

Добавлено в версии 0.11: SESSION_REFRESH_EACH_REQUEST, TEMPLATES_AUTO_RELOAD, LOGGER_HANDLER_POLICY, EXPLAIN_TEMPLATE_LOADING

Изменено в версии 1.0: LOGGER_NAME и LOGGER_HANDLER_POLICY были удалены. Информацию о конфигурации смотрите в Ведение журнала.

Добавлена ENV для отражения переменной окружения FLASK_ENV.

Добавлено SESSION_COOKIE_SAMESITE для управления параметром SameSite сессионного cookie.

Добавлено MAX_COOKIE_SIZE для управления предупреждением от Werkzeug.

Конфигурирование из файлов

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

Итак, общая схема такова:

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. В дальнейшем в объекте config будут храниться только значения в верхнем регистре. Поэтому обязательно используйте заглавные буквы для ключей конфигурации.

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

# Example configuration
DEBUG = False
SECRET_KEY = b'_5#y2L"F4Q8z\n\xec]/'

Обязательно загрузите конфигурацию на самом раннем этапе, чтобы расширения имели возможность доступа к ней при запуске. Существуют и другие методы объекта config для загрузки из отдельных файлов. Для получения полной информации прочтите документацию объекта Config.

Настройка из переменных среды

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

Переменные окружения можно установить в Linux или OS X с помощью команды export в оболочке перед запуском сервера:

$ export SECRET_KEY='5f352379324c22463451387a0aec5d2f'
$ export MAIL_ENABLED=false
$ python run-app.py
 * Running on http://127.0.0.1:5000/

В системах Windows вместо этого используйте встроенную функцию set:

> set SECRET_KEY='5f352379324c22463451387a0aec5d2f'

Хотя этот подход прост в использовании, важно помнить, что переменные окружения являются строками - они не десериализуются автоматически в типы 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")

Обратите внимание, что любое значение, кроме пустой строки, будет интерпретироваться в Python как булево значение True, что требует осторожности, если среда явно устанавливает значения, предназначенные для False.

Обязательно загрузите конфигурацию на самом раннем этапе, чтобы расширения имели возможность доступа к ней при запуске. Существуют и другие методы объекта config для загрузки из отдельных файлов. Для получения полной информации ознакомьтесь с документацией класса Config.

Лучшие практики конфигурирования

Недостатком упомянутого выше подхода является то, что он делает тестирование немного сложнее. Не существует единого 100% решения этой проблемы в целом, но есть несколько вещей, которые можно иметь в виду, чтобы улучшить этот опыт:

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

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

Разработка / Производство

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

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):
    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')

Обратите внимание, что 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."""
    DEBUG = False
    TESTING = False
    DB_SERVER = '192.168.1.56'

    @property
    def DATABASE_URI(self):         # Note: all caps
        return 'mysql://user@{}/foo'.format(self.DB_SERVER)

class ProductionConfig(Config):
    """Uses production database server."""
    DB_SERVER = '192.168.19.32'

class DevelopmentConfig(Config):
    DB_SERVER = 'localhost'
    DEBUG = True

class TestingConfig(Config):
    DB_SERVER = 'localhost'
    DEBUG = True
    DATABASE_URI = 'sqlite:///:memory:'

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

  • Храните конфигурацию по умолчанию в системе контроля версий. Либо заполните конфигурацию этой конфигурацией по умолчанию, либо импортируйте ее в свои собственные конфигурационные файлы, прежде чем переопределять значения.

  • Используйте переменную окружения для переключения между конфигурациями. Это может быть сделано вне интерпретатора Python и значительно упрощает разработку и развертывание, поскольку вы можете быстро и легко переключаться между различными конфигурациями, не касаясь кода. Если вы часто работаете над разными проектами, вы даже можете создать собственный скрипт для сорсинга, который активирует virtualenv и экспортирует конфигурацию разработки для вас.

  • Используйте такой инструмент, как fabric в продакшене для отдельной отправки кода и конфигураций на продакшен-сервер(ы). Для получения подробной информации о том, как это сделать, перейдите к шаблону Развертывание с помощью 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/python2.X/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()