Skip to main content

Display loaders without requiring AJAX

Project description

Flask-Suspense

Display loaders without requiring AJAX. Use streaming templates to delay the rendering of parts of the template to the end of the response.

This is similar to React's Suspense and Next.js data loading mechanism.

Installation

pip install flask-suspense

Usage

Enable the Suspense extension. Decorate your long running data loader using @defer and pass it to the template. Render the template using flask_suspense.render_template.

from flask import Flask
from flask_suspense import Suspense, defer, render_template

app = Flask(__name__)
Suspense(app)

@app.route('/')
def index():

    @defer
    def data():
        time.sleep(2)  # Simulate a long-running process
        return "Loaded data"
    
    return render_template('index.html', data=data)

In your template, use the {% suspense %} block to defer rendering to the end of the template.

{% suspense %}
    {{ data }}
{% endsuspense %}

You can also display a loading message:

{% suspense %}
    {{ data }}
{% fallback %}
    <p>Loading...</p>
{% endsuspense %}

[!TIP] The {% suspense %} block does not require the use of @defer loaders. It will simply delay the rendering of its content to the end of the template.

[!WARNING] Using Flask.render_template() will not render the suspense blocks

You can disable suspense by passing _suspense_disabled=True to render_template().

[!TIP] flask_suspense.stream_template() is also available

Usage with Content Securiy Policy (CSP)

Using suspense blocks will use inline script tags. This may conflict with your content security policy.

A nonce can be provided to ensure the script tag is allowed. Set the nonce via g.suspense_nonce.

@app.before_request
def setup_nonce():
    g.suspense_nonce = "random string"

@app.after_request
def setup_csp(resp):
    resp.headers['Content-Security-Policy'] = f"script-src 'nonce-{g.suspense_once}';"
    return resp

About the loader

A loading div will be inserted in place of your suspense block. This div has a suspense-loader class. It will be replaced once the content is loaded.

How does it work ?

Streaming responses allow to start sending back to the response in multiple parts.

When rendering, {% suspense %} blocks are converted to macros and replaced by a loading div at the location they have been used.

The template is rendered in full first, without calling the suspense macros. It is sent back to the client.

Suspense macros are then called and their results are sent back wrapped in script tags that replace the loaders.

@defer loaders ensures that the data loading will only start when the object is called as part of the macro, at the end of the stream.

Customizing how content is inserted

When a suspense block is sent to the client, it replaces the loader using a simple document.getElementById(suspenseId).outerHTML = suspenseBlockHtml.

This can be customized by providing a custom function window.__replace_suspense__ on the frontend.

<script>
    window.__replace_suspense__ = (id, html) => {
        console.log(`Received suspense block ${id}`)
        document.getElementById(id).outerHTML = html;
    };
</script>

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flask_suspense-0.1.0.tar.gz (3.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flask_suspense-0.1.0-py3-none-any.whl (4.6 kB view details)

Uploaded Python 3

File details

Details for the file flask_suspense-0.1.0.tar.gz.

File metadata

  • Download URL: flask_suspense-0.1.0.tar.gz
  • Upload date:
  • Size: 3.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.17

File hashes

Hashes for flask_suspense-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4e18374ae8b41f2be79d2491c05f28f77619bdf642bd275b526ebbeb2e6b4351
MD5 db2a0efb4e61fa6434fabc6b1fe08e92
BLAKE2b-256 122254e8656d8c7bd67dafd7059bee07a6366a024dabe74ba26580db713e6fb1

See more details on using hashes here.

File details

Details for the file flask_suspense-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for flask_suspense-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 dbdf98d9058b5f8771500a799ae62b06a4a76f1040f1e5236f82e43edc118b10
MD5 a2f2a9168c5e633497732ed4e5f06d26
BLAKE2b-256 6a5ae7c47af34d5429fbc438f528df7da061f0a66fc8b2c513d80b7f06a8863d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page