Spec-Zone.ru › Flask 2.1

Потоковая передача содержимого

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

Ответ — использование генераторов и прямых ответов.

Основное использование

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

@app.route('/large.csv')
def generate_large_csv():
    def generate():
        for row in iter_all_rows():
            yield f"{','.join(row)}\n"
    return app.response_class(generate(), mimetype='text/csv')

Каждое yield выражение отправляется непосредственно в браузер. Однако следует помнить, что некоторые WSGI-мидлвары могут нарушить потоковую передачу, поэтому будьте осторожны в средах отладки с профилировщиками и другими включенными инструментами.

Потоковая передача из шаблонов

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

def stream_template(template_name, **context):
    app.update_template_context(context)
    t = app.jinja_env.get_template(template_name)
    rv = t.stream(context)
    rv.enable_buffering(5)
    return rv

@app.route('/my-large-page.html')
def render_large_template():
    rows = iter_all_rows()
    return app.response_class(stream_template('the_template.html', rows=rows))

Суть в том, чтобы получить объект шаблона из окружения Jinja2 в приложении и вызвать stream() вместо render(), что возвращает объект потока, а не строку. Поскольку мы минуем функции рендеринга шаблонов Flask и используем сам объект шаблона, мы должны сами обновлять контекст рендеринга, вызвав update_template_context(). Шаблон затем оценивается по мере итерации по потоку. Поскольку каждый раз, когда вы выполняете yield, сервер будет отправлять содержимое клиенту, вы можете буферизовать несколько элементов в шаблоне, что можно сделать с помощью rv.enable_buffering(size). 5 является разумным значением по умолчанию.

Потоковая передача с контекстом

Журнал изменений

Введено в версии 0.9.

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

from flask import stream_with_context, request

@app.route('/stream')
def streamed_response():
    def generate():
        yield 'Hello '
        yield request.args['name']
        yield '!'
    return app.response_class(stream_with_context(generate()))

Без функции stream_with_context() вы получите RuntimeError в этот момент.

© 2007–2022 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.1.x/patterns/streaming/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API