Quick Start¶
How to Install¶
pip install turbo-flask
How to Add to your Project¶
Direct initialization:
from flask import Flask
from turbo_flask import Turbo
app = Flask(__name__)
turbo = Turbo(app)
Factory function initialization:
from flask import Flask
from turbo_flask import Turbo
turbo = Turbo()
def create_app():
app = Flask(__name__)
turbo.init_app(app)
return app
To add Turbo-Flask to your pages, include {{ turbo() }}
in the <head>
element of your main Jinja template:
<!doctype html>
<html>
<head>
{{ turbo() }}
</head>
<body>
...
</body>
</html>
Configuration¶
Configuration for this extension is given through the Flask configuration object. There is only one configuration variable supported by this extension:
TURBO_WEBSOCKET_ROUTE
: The route URL on which the client can connect using WebSocket to receive Turbo Stream updates. By default, the/turbo-stream
URL is used. If this variable is set toNone
, the WebSocket endpoint is disabled.
How to Use¶
The Turbo Drive and Turbo Frames features provided by turbo.js do not require server side support, so access to these features in your templates is enabled just by adding the library as indicated above. Consult the turbo.js documentation to learn how to take advantage of these features.
However, if you decide to use the Turbo Streams feature of turbo.js, this extension has helpers to generate correctly formatted streams.
The turbo
object has five helper methods that generate the different types
of Turbo Stream operations:
turbo.append(content, target)
: addcontent
at the end oftarget
turbo.prepend(content, target)
: addcontent
at the start oftarget
turbo.replace(content, target)
: replacetarget
withcontent
turbo.update(content, target)
: replace the contents oftarget
withcontent
turbo.remove(target)
: removetarget
In all these methods, content
is a string with HTML content, usually the
result of invoking Flask’s render_template()
function. The target
argument is the id of the element in the page that will be modified.
There are two supported use cases for the Turbo Streams feature: a response to a POST request, and a server-push update over WebSocket. The following sections describe how to deliver streams for both.
Responding to a POST Request with a Turbo Stream¶
The following example shows how to deliver a Turbo Stream as a response to a POST request:
if turbo.can_stream():
return turbo.stream(
turbo.append(render_template('_todo.html', todo=todo), target='todos'),
)
else:
return render_template('index.html', todos=todos)
Here is another example using a list of updates:
if turbo.can_stream():
return turbo.stream([
turbo.append(render_template('_todo.html', todo=todo), target='todos'),
turbo.update(render_template('_todo_input.html'), target='form')
])
else:
return render_template('index.html', todos=todos)
The turbo.stream()
method takes one or a list of Turbo Stream updates and
generates a Turbo Stream response that can be returned directly from the Flask
view function.
The turbo.can_stream()
method is a helper methods that returns True
if
the client indicated that it supports Turbo Stream responses. It is a good idea
to fall back to a standard Flask response when Turbo Streams aren’t accepted by
the client, as shown in the above examples.
Pushing Updates via WebSocket Streaming¶
The application can, at any time, push updates to parts of the page using the
turbo.push()
helper method. Below you can see a simple example:
def update_load():
with app.app_context():
while True:
time.sleep(5)
turbo.push(turbo.replace(render_template('loadavg.html'), 'load'))
In the above example the turbo.push()
method will send the update to all
connected clients.
The turbo.push()
method supports an optional to
argument that can be
used to select one or more specific clients to receive the update. To take
advantage of this, the application first needs to provide a function that
assigns an id to each connected client, and decorate it with the
turbo.user_id
decorator. In the following example, the id for each client
is obtained from Flask-Login’s current_user
:
@turbo.user_id
def get_user_id():
return current_user.id
To push an update to a given client, the to
argument can be added to the
turbo.push()
method:
turbo.push(turbo.replace(render_template('loadavg.html'), 'load'),
to=admin_user_id)
It is also possible to send the update to multiple clients by passing a list
in the to
argument:
turbo.push(turbo.replace(render_template('loadavg.html'), 'load'),
to=[admin_user_id, moderator_user_id])
Deployment¶
This extension implementes a WebSocket endpoint. The default location for this
endpoint is /turbo-stream
, but this can be changed by setting the
TURBO_WEBSOCKET_ROUTE
configuration variable.
When using a reverse proxy in front of the Flask application, the WebSocket
endpoint may need a special configuration to work correctly. For example, in
Nginx, the endpoint must be configured to explicitly forward the Upgrade
and Connection
headers, which are not proxied by default. While the actual
configuration may vary according to the needs of each application, the
following example can be used as a starting point:
location /turbo-stream {
include proxy_params;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://localhost:5000;
}
The WebSocket support in this extension is provided by the Flask-Sock package, which supports WebSocket servers based on Gunicorn, Eventlet, Gevent and the Flask development web server. Refer to the Flask-Sock documentation for additional deployment details.