Spec-Zone.ru › Flask 1.1

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

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

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

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

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

from flask import Response

@app.route('/large.csv')
def generate_large_csv():
    def generate():
        for row in iter_all_rows():
            yield ','.join(row) + '\n'
    return Response(generate(), mimetype='text/csv')

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

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

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

from flask import Response

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 Response(stream_template('the_template.html', rows=rows))

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

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

Changelog

Новая функция в версии 0.9.

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

from flask import stream_with_context, request, Response

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

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

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

Spec-Zone.ru

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