### app_context Используется для доступа к экземпляру приложения вне запроса. Он позволяет получить доступ к конфигурации приложения, расширениям Flask и другим объектам, которые доступны только на этапе создания приложения. Чтобы использовать app_context в Flask, вам нужно создать экземпляр приложения, а затем создать контекст приложения с помощью метода app.app_context(). После этого вы можете выполнять любой код, который требует доступа к экземпляру приложения. ``` from flask import Flask app = Flask(__name__) app.config['DEBUG'] = True with app.app_context(): # Выполнение кода, который требует доступа к экземпляру приложения print(app.config['DEBUG']) ``` Вы также можете использовать app_context в функции Flask, чтобы получить доступ к экземпляру приложения, например, так: ``` from flask import Flask, current_app app = Flask(__name__) @app.route('/') def index(): app = current_app._get_current_object() # Выполнение кода, который требует доступа к экземпляру приложения return 'Hello World!' ``` ### Декоратор before_first_request Позволяет определить функцию, которая будет выполнена перед обработкой первого запроса. Это может быть полезно, если вам нужно выполнить какую-то инициализацию перед запуском приложения. ``` from flask import Flask app = Flask(__name__) @app.before_first_request def init_app(): # выполнение инициализации приложения перед первым запросом print('Application initialized.') @app.route('/') def index(): return 'Hello, world!' if __name__ == '__main__': app.run() ``` ### Метод log_exception Используется для логирования исключений, возникших во время обработки запроса. Этот метод вызывается автоматически, если происходит исключение во время выполнения запроса. log_exception принимает три аргумента: тип исключения exc_info, который представляет кортеж из трех значений (тип, значение и трассировку стека); имя функции function_name, в которой возникло исключение, и информацию о запросе request. ``` from flask import Flask, request import logging app = Flask(__name__) @app.route('/') def index(): return 1/0 @app.after_request def after_request(response): if response.status_code != 500: return response app.logger.error('Unhandled Exception: %s', (exc_info := request.exc_info)) return response if __name__ == '__main__': logging.basicConfig(filename='app.log', level=logging.DEBUG) app.run(debug=True) ``` ### Функция make_aborter Позволяет создавать персонализированные объекты HTTPException, которые могут использоваться для прерывания обработки запроса и возвращения соответствующего HTTP-статуса кода и сообщения об ошибке. make_aborter принимает словарь, в котором каждый ключ соответствует коду ошибки HTTP, а значение - пользовательскому сообщению об ошибке, которое будет возвращено вместе со статусом кодом при вызове объекта HTTPException. Вот пример использования make_aborter для создания объекта HTTPException с пользовательским сообщением об ошибке: ``` from flask import Flask, abort, make_response, jsonify app = Flask(__name__) error_messages = { 400: 'Bad Request', 401: 'Unauthorized', 403: 'Forbidden', 404: 'Not Found', 500: 'Internal Server Error' } aborter = make_aborter(error_messages) @app.route('/') def index(): aborter(404) if __name__ == '__main__': app.run(debug=True) ``` ### make_response Позволяет создавать объект Response для ответа на запрос. Она принимает три аргумента: * response: объект, который будет использоваться в качестве ответа на запрос. Это может быть строка, объект jsonify, объект render_template, файл и т.д. * status: HTTP-статус код, который будет возвращен вместе с ответом на запрос. По умолчанию это 200 (OK). * headers: список заголовков HTTP, которые будут добавлены к ответу на запрос. Это может быть словарь с ключами и значениями заголовков, или список кортежей, где каждый кортеж представляет собой заголовок и его значение. ``` from flask import Flask, jsonify, make_response app = Flask(__name__) @app.route('/') def index(): data = {'message': 'Hello, World!'} response = jsonify(data) response.headers['Content-Type'] = 'application/json' return make_response(response, 200) if __name__ == '__main__': app.run(debug=True) ``` ### Декоратор process_response Позволяет обрабатывать ответы на запросы перед тем, как они будут отправлены клиенту. Функция, которая будет использоваться в качестве обработчика, должна принимать два аргумента: response и request. response - это объект Response, который будет отправлен клиенту, а request - объект Request, который был использован для отправки запроса. ``` from flask import Flask, Response, request app = Flask(__name__) @app.route('/') def index(): return 'Hello, World!' @app.after_request def add_header(response): response.headers['X-My-Header'] = 'Custom Header' return response if __name__ == '__main__': app.run(debug=True) ``` ### Декоратор teardown_appcontext Регистрирует функцию, которая будет вызываться после завершения обработки запроса и передачи управления объекту контекста приложения. Контекст приложения - это объект, который хранит состояние приложения, доступное в рамках текущего запроса. Он содержит информацию, такую как база данных, авторизация пользователя, конфигурация приложения и многое другое. Декоратор teardown_appcontext позволяет зарегистрировать функцию, которая будет выполняться после завершения обработки запроса и передачи управления объекту контекста приложения. Это может быть полезно для выполнения дополнительных задач, таких как закрытие соединения с базой данных или удаление временных файлов. ``` from flask import Flask, g, request app = Flask(__name__) app.config['DATABASE'] = 'path/to/database' def get_db(): if not hasattr(g, 'db'): g.db = connect_to_database(app.config['DATABASE']) return g.db @app.teardown_appcontext def close_db(exception): db = getattr(g, 'db', None) if db is not None: db.close() @app.route('/') def index(): db = get_db() # делаем запросы к базе данных return 'Hello, World!' if __name__ == '__main__': app.run(debug=True) ``` ### Метод do_teardown_request Вызывается после того, как запрос был обработан и ответ был отправлен клиенту. Этот метод выполняет некоторые действия по очистке, завершению и закрытию объектов, которые были созданы во время обработки запроса. Например, он закрывает соединения с базой данных, которые были открыты во время обработки запроса. Встроенные функции Flask обычно автоматически вызывают do_teardown_request, но если вам нужно выполнить какие-то дополнительные действия после завершения запроса, вы можете зарегистрировать функцию с помощью декоратора @app.teardown_request. ``` from flask import Flask, g, request app = Flask(__name__) app.config['DATABASE'] = 'path/to/database' def get_db(): if not hasattr(g, 'db'): g.db = connect_to_database(app.config['DATABASE']) return g.db @app.teardown_request def close_db(exception=None): db = getattr(g, 'db', None) if db is not None: db.close() @app.route('/') def index(): db = get_db() # делаем запросы к базе данных return 'Hello, World!' if __name__ == '__main__': app.run(debug=True) ``` ### Метод teardown_appcontext Вызывается после завершения работы приложения, когда контекст приложения больше не нужен. Этот метод может быть использован для выполнения некоторых действий по завершению работы приложения. Например, он может закрыть соединения с базой данных, завершить сессии пользователей, удалить временные файлы и т.д. Вы можете зарегистрировать функцию, которая будет вызываться после завершения работы приложения, с помощью декоратора @app.teardown_appcontext. Пример: ``` from flask import Flask app = Flask(__name__) @app.teardown_appcontext def cleanup_db(exception): # закрыть соединение с базой данных db_session.close() if __name__ == '__main__': app.run(debug=True) ``` Чтобы установить заголовки ответа для всех маршрутов и представлений в приложении Flask, вы можете использовать декоратор after_request. Декоратор after_request регистрирует функцию, которая вызывается после того, как запрос был обработан и готов к отправке ответа. ``` from flask import Flask, jsonify app = Flask(__name__) @app.after_request def add_headers(response): response.headers['X-Content-Type-Options'] = 'nosniff' response.headers['X-Frame-Options'] = 'SAMEORIGIN' response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains; preload' response.headers['X-XSS-Protection'] = '1; mode=block' response.headers['Referrer-Policy'] = 'no-referrer-when-downgrade' response.headers['Content-Type'] = 'text/html; charset=utf-8' return response @app.route('/') def index(): data = {'message': 'Hello, World!'} return jsonify(data) if __name__ == '__main__': app.run() ``` ## Bleuprints Что что можно применять к приложению можно и применить к конкретному blueprint-у ## Метод after_app_request Позволяет зарегистрировать функцию, которая будет вызываться после того, как запрос был обработан приложением. Этот метод работает аналогично глобальному after_request методу приложения Flask, но он применяется только к маршрутам, зарегистрированным в данном Blueprint. Вы можете использовать метод after_app_request для выполнения каких-либо действий после завершения запроса, например, для логирования или сохранения данных. Функция, которую вы зарегистрируете с помощью after_app_request, должна принимать объект ответа Flask и возвращать его без изменений. ``` from flask import Flask, Blueprint app = Flask(__name__) bp = Blueprint('my_blueprint', __name__) @bp.route('/hello') def hello(): return 'Hello, World!' def after_request(response): # Do some logging or processing with the response object return response bp.after_app_request(after_request) app.register_blueprint(bp) if __name__ == '__main__': app.run(debug=True) ``` ### Метод before_request Позволяет зарегистрировать функцию, которая будет вызываться перед тем, как запрос будет обработан приложением. Этот метод работает аналогично глобальному before_request методу приложения Flask, но он применяется только к маршрутам, зарегистрированным в данном Blueprint. Вы можете использовать метод before_request для выполнения каких-либо действий перед обработкой запроса, например, для проверки аутентификации пользователя или для установки контекста приложения. Функция, которую вы зарегистрируете с помощью before_request, может принимать произвольное число аргументов, но она должна вернуть None или объект ответа Flask. ``` from flask import Flask, Blueprint, request, abort app = Flask(__name__) bp = Blueprint('my_blueprint', __name__) @bp.route('/hello') def hello(): return 'Hello, World!' def before_request(): if request.headers.get('X-Secret-Key') != 'my-secret-key': abort(401) bp.before_request(before_request) app.register_blueprint(bp) if __name__ == '__main__': app.run(debug=True) ``` ## Полезные функции ### Декоратор after_this_request Позволяет добавить функцию, которая будет вызвана после того, как будет сформирован ответ на текущий запрос. Это может быть полезно, если вы хотите выполнить какое-то действие после того, как ответ был отправлен клиенту. ``` @app.route('/') def index(): @after_this_request def add_header(response): response.headers['X-Foo'] = 'Parachute' return response return 'Hello World!' ``` ### функция stream_with_context Позволяет создать контекстный менеджер для потока, связанного с запросом. При работе с запросами, которые возвращают большие объемы данных, может возникнуть необходимость поэтапной отправки данных клиенту. Например, если вы отправляете файл размером несколько гигабайт, вы не хотите дожидаться полной загрузки файла на сервере, прежде чем начать отправку данных клиенту. Для этого вы можете использовать функцию stream_with_context, которая позволяет считывать данные из файла по частям и отправлять их в виде потока. ``` from flask import Flask, Response, stream_with_context app = Flask(__name__) @app.route('/download') def download(): def generate(): with open('largefile.csv', 'r') as f: while True: chunk = f.read(1024) if not chunk: break yield chunk response = Response(stream_with_context(generate())) response.headers.set('Content-Disposition', 'attachment', filename='largefile.csv') response.headers.set('Content-Type', 'text/csv') return response ```