Updated docs for streaming
This commit is contained in:
parent
343e678900
commit
4d2c8181b4
2 changed files with 71 additions and 0 deletions
|
|
@ -35,3 +35,4 @@ Snippet Archives <http://flask.pocoo.org/snippets/>`_.
|
|||
lazyloading
|
||||
mongokit
|
||||
favicon
|
||||
streaming
|
||||
|
|
|
|||
70
docs/patterns/streaming.rst
Normal file
70
docs/patterns/streaming.rst
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
Streaming Contents
|
||||
==================
|
||||
|
||||
Sometimes you want to send an enormous amount of data to the client, much
|
||||
more than you want to keep in memory. When you are generating the data on
|
||||
the fly though, how do you send that back to the client without the
|
||||
roundtrip to the filesystem?
|
||||
|
||||
The answer is by using generators and direct responses.
|
||||
|
||||
Basic Usage
|
||||
-----------
|
||||
|
||||
This is a basic view function that generates a lot of CSV data on the fly.
|
||||
The trick is to have an inner function that uses a generator to generate
|
||||
data and to then invoke that function and pass it to a response object
|
||||
that has the ``direct_passthrough`` flag set. This flag is used to inform
|
||||
the system that data is generated on the fly and should be passed through
|
||||
without buffering:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
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(), direct_passthrough=True,
|
||||
mimetype='text/csv')
|
||||
|
||||
Each ``yield`` expression is directly sent to the browser. Now though
|
||||
that some WSGI middlewares might break streaming, so be careful there in
|
||||
debug environments with profilers and other things you might have enabled.
|
||||
|
||||
Streaming from Templates
|
||||
------------------------
|
||||
|
||||
The Jinja2 template engine also supports rendering templates piece by
|
||||
piece. This functionality is not directly exposed by Flask because it is
|
||||
quite uncommon, but you can easily do it yourself:
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
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),
|
||||
direct_passthrough=True)
|
||||
|
||||
The trick here is to get the template object from the Jinja2 environment
|
||||
on the application and to call :meth:`~jinja2.Template.stream` instead of
|
||||
:meth:`~jinja2.Template.render` which returns a stream object instead of a
|
||||
string. Since we're bypassing the Flask template render functions and
|
||||
using the template object itself we have to make sure to update the render
|
||||
context ourselves by calling :meth:`~flask.Flask.update_template_context`.
|
||||
The template is then evaluated as the stream is iterated over. Since each
|
||||
time you do a yield the server will flush the content to the client you
|
||||
might want to buffer up a few items in the template which you can do with
|
||||
``rv.enable_buffering(size)``. ``5`` is a sane default.
|
||||
Loading…
Add table
Add a link
Reference in a new issue