ストリーミングコンテンツ
場合によっては、メモリに保持したいよりもはるかに多くのデータをクライアントに送信したいことがあります。 ただし、その場でデータを生成する場合、ファイルシステムへのラウンドトリップなしで、どのようにデータをクライアントに送り返しますか?
答えは、ジェネレーターと直接応答を使用することです。
基本的な使用法
これは、大量の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テンプレートエンジンは、テンプレートを1つずつレンダリングすることもサポートしています。 この機能は非常にまれであるため、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環境からテンプレートオブジェクトを取得し、文字列の代わりにストリームオブジェクトを返すrender()
の代わりにstream()
を呼び出すことです。 Flaskテンプレートのレンダリング関数をバイパスし、テンプレートオブジェクト自体を使用しているため、update_template_context()
を呼び出して、レンダリングコンテキストを自分で更新する必要があります。 次に、ストリームが繰り返されるときにテンプレートが評価されます。 イールドを実行するたびに、サーバーはコンテンツをクライアントにフラッシュするため、rv.enable_buffering(size)
で実行できるテンプレート内のいくつかのアイテムをバッファリングする必要がある場合があります。 5
は適切なデフォルトです。
コンテキストを使用したストリーミング
バージョン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
が得られます。