Spec-Zone.ru › Flask 2.2

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

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

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

Основные принципы

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

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

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

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

Движок шаблонов Jinja2 поддерживает поблочное рендеринг шаблона, возвращая итератор строк. Flask предоставляет функции stream_template() и stream_template_string() для упрощения использования.

from flask import stream_template

@app.get("/timeline")
def timeline():
    return stream_template("timeline.html")

Части, возвращаемые потоком рендеринга, обычно соответствуют блокам инструкций в шаблоне.

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

Объект request не будет активным во время работы генератора, потому что представление уже вернуло результат к этому моменту. Если вы попытаетесь получить доступ к request, получите RuntimeError.

Если ваша функция-генератор зависит от данных в request, используйте обёртку stream_with_context(). Это позволит сохранить контекст запроса активным во время работы генератора.

from flask import stream_with_context, request
from markupsafe import escape

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

Также её можно использовать как декоратор.

@stream_with_context
def generate():
    ...

return generate()

Функции stream_template() и stream_template_string() автоматически используют stream_with_context(), если запрос активен.

© 2010 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/stable/patterns/streaming/

Spec-Zone.ru

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