forked from orbit-oss/flask
add generate_template and generate_template_string functions
This commit is contained in:
parent
762382e436
commit
46433e9807
7 changed files with 139 additions and 37 deletions
|
|
@ -287,6 +287,10 @@ Template Rendering
|
|||
|
||||
.. autofunction:: render_template_string
|
||||
|
||||
.. autofunction:: stream_template
|
||||
|
||||
.. autofunction:: stream_template_string
|
||||
|
||||
.. autofunction:: get_template_attribute
|
||||
|
||||
Configuration
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ data and to then invoke that function and pass it to a response object::
|
|||
def generate():
|
||||
for row in iter_all_rows():
|
||||
yield f"{','.join(row)}\n"
|
||||
return app.response_class(generate(), mimetype='text/csv')
|
||||
return generate(), {"Content-Type": "text/csv")
|
||||
|
||||
Each ``yield`` expression is directly sent to the browser. Note though
|
||||
that some WSGI middlewares might break streaming, so be careful there in
|
||||
|
|
@ -29,52 +29,57 @@ 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::
|
||||
The Jinja2 template engine supports rendering a template piece by
|
||||
piece, returning an iterator of strings. Flask provides the
|
||||
:func:`~flask.stream_template` and :func:`~flask.stream_template_string`
|
||||
functions to make this easier to use.
|
||||
|
||||
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
|
||||
.. code-block:: python
|
||||
|
||||
@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))
|
||||
from flask import stream_template
|
||||
|
||||
@app.get("/timeline")
|
||||
def timeline():
|
||||
return stream_template("timeline.html")
|
||||
|
||||
The parts yielded by the render stream tend to match statement blocks in
|
||||
the template.
|
||||
|
||||
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.
|
||||
|
||||
Streaming with Context
|
||||
----------------------
|
||||
|
||||
.. versionadded:: 0.9
|
||||
The :data:`~flask.request` will not be active while the generator is
|
||||
running, because the view has already returned at that point. If you try
|
||||
to access ``request``, you'll get a ``RuntimeError``.
|
||||
|
||||
Note that when you stream data, the request context is already gone the
|
||||
moment the function executes. Flask 0.9 provides you with a helper that
|
||||
can keep the request context around during the execution of the
|
||||
generator::
|
||||
If your generator function relies on data in ``request``, use the
|
||||
:func:`~flask.stream_with_context` wrapper. This will keep the request
|
||||
context active during the generator.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from flask import stream_with_context, request
|
||||
from markupsafe import escape
|
||||
|
||||
@app.route('/stream')
|
||||
def streamed_response():
|
||||
def generate():
|
||||
yield 'Hello '
|
||||
yield request.args['name']
|
||||
yield '!'
|
||||
return app.response_class(stream_with_context(generate()))
|
||||
yield '<p>Hello '
|
||||
yield escape(request.args['name'])
|
||||
yield '!</p>'
|
||||
return stream_with_context(generate())
|
||||
|
||||
Without the :func:`~flask.stream_with_context` function you would get a
|
||||
:class:`RuntimeError` at that point.
|
||||
It can also be used as a decorator.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@stream_with_context
|
||||
def generate():
|
||||
...
|
||||
|
||||
return generate()
|
||||
|
||||
The :func:`~flask.stream_template` and
|
||||
:func:`~flask.stream_template_string` functions automatically
|
||||
use :func:`~flask.stream_with_context` if a request is active.
|
||||
|
|
|
|||
|
|
@ -201,3 +201,29 @@ templates::
|
|||
You could also build `format_price` as a template filter (see
|
||||
:ref:`registering-filters`), but this demonstrates how to pass functions in a
|
||||
context processor.
|
||||
|
||||
Streaming
|
||||
---------
|
||||
|
||||
It can be useful to not render the whole template as one complete
|
||||
string, instead render it as a stream, yielding smaller incremental
|
||||
strings. This can be used for streaming HTML in chunks to speed up
|
||||
initial page load, or to save memory when rendering a very large
|
||||
template.
|
||||
|
||||
The Jinja2 template engine supports rendering a template piece
|
||||
by piece, returning an iterator of strings. Flask provides the
|
||||
:func:`~flask.stream_template` and :func:`~flask.stream_template_string`
|
||||
functions to make this easier to use.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from flask import stream_template
|
||||
|
||||
@app.get("/timeline")
|
||||
def timeline():
|
||||
return stream_template("timeline.html")
|
||||
|
||||
These functions automatically apply the
|
||||
:func:`~flask.stream_with_context` wrapper if a request is active, so
|
||||
that it remains available in the template.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue