35

I want to display my CPU usage dynamically. I don't want to reload the page to see a new value. I know how to get the CPU usage in Python. Right now I render a template with the value. How can I continually update a page with a value from Flask?

@app.route('/show_cpu')
def show_cpu():
    cpu = getCpuLoad()
    return render_template('show_cpu.html', cpu=cpu)
davidism
  • 121,510
  • 29
  • 395
  • 339
Depado
  • 4,811
  • 3
  • 41
  • 63
  • 1
    not reloading the page means you have to execute code from the client, which means you **have** to use javascript. Also, when you say CPU usage do you mean your server's? – Nadir Sampaoli Mar 30 '13 at 18:04
  • 1
    Yup, you have to use JavaScript to make a query to the server to get an update on the CPU usage. Not possible to do this entirely from the server side. – aychedee Mar 30 '13 at 18:13
  • 4
    If you established a websocket connection, then the server could push updates to the client. But you would still be using JS to create the connection and deal with the updates from the server. – aychedee Mar 30 '13 at 18:16
  • Does anyone have an example of ajax request to get variables ? :/ – Depado Apr 03 '13 at 07:01
  • 1
    http://docs.jquery.com/Tutorials:Quick_and_Dirty_Ajax – David K. Hess Apr 03 '13 at 12:08
  • I edited the answer, now there is an example using websockets. – Depado Aug 29 '14 at 07:57
  • Also relevant: [How to implement server push in Flask framework?](https://stackoverflow.com/questions/12232304/how-to-implement-server-push-in-flask-framework) – ggorlen Aug 06 '22 at 01:25

1 Answers1

34

Using an Ajax request

Python

@app.route('/_stuff', methods= ['GET'])
def stuff():
    cpu=round(getCpuLoad())
    ram=round(getVmem())
    disk=round(getDisk())
    return jsonify(cpu=cpu, ram=ram, disk=disk)

Javascript

function update_values() {
            $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
            $.getJSON($SCRIPT_ROOT+"/_stuff",
                function(data) {
                    $("#cpuload").text(data.cpu+" %")
                    $("#ram").text(data.ram+" %")
                    $("#disk").text(data.disk+" %")
                });
        }

Using Websockets

project/app/views/request/websockets.py

# -*- coding: utf-8 -*-

# OS Imports
import json

# Local Imports
from app import sockets
from app.functions import get_cpu_load, get_disk_usage, get_vmem

@sockets.route('/_socket_system')
def socket_system(ws):
    """
    Returns the system informations, JSON Format
    CPU, RAM, and Disk Usage
    """
    while True:
        message = ws.receive()
        if message == "update":
            cpu = round(get_cpu_load())
            ram = round(get_vmem())
            disk = round(get_disk_usage())
            ws.send(json.dumps(dict(received=message, cpu=cpu, ram=ram, disk=disk)))
        else:
            ws.send(json.dumps(dict(received=message)))

project/app/__init__.py

# -*- coding: utf-8 -*-
from flask import Flask
from flask_sockets import Sockets


app = Flask(__name__)
sockets = Sockets(app)
app.config.from_object('config')
from app import views

Using Flask-Websockets made my life a lot easier. Here is the launcher : launchwithsockets.sh

#!/bin/sh

gunicorn -k flask_sockets.worker app:app

Finally, here is the client code :
custom.js
The code is a bit too long, so here it is.
Note that I'm NOT using things like socket.io, that's why the code is long. This code also tries to reconnect to the server periodically, and can stop trying to reconnect on a user action. I use the Messenger lib to notify the user that something went wrong. Of course it's a bit more complicated than using socket.io but I really enjoyed coding the client side.

Depado
  • 4,811
  • 3
  • 41
  • 63
  • The ajax code gives me the error Uncaught ReferenceError: $SCRIPT_ROOT is not defined – Marshall Mar 24 '16 at 14:04
  • Have a look at the documentation here : http://flask.pocoo.org/docs/0.10/patterns/jquery/#where-is-my-site – Depado Mar 29 '16 at 13:20
  • `setInterval(update_values, 1000)` will call that function every second, see : https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval – Depado Nov 25 '16 at 13:36
  • 1
    What webpage are you returning when you call the route with jsonify? How is this information put on the front-end? – secretagentmango Jul 30 '19 at 22:05
  • @secretagentmango No webpage is returned, only JSON. The frontend calls that route using an Ajax request and parses the returned JSON. See the Javascript snippet in the answer to see an example :) – Depado Jul 31 '19 at 15:14
  • @Depado, thank you for your answer. My beginner question concerning Ajax is similar to the one above. You mention no webpage is returned, so no .html file under templates. So where does the javascript go? – Zhubarb Jan 07 '20 at 17:09
  • @Zhubarb First you will render your html page (template). This page will contain the JS code. This JS code will then call the AJAX route which will only return JSON data. – Depado Feb 10 '20 at 14:08
  • @Depado regarding the Ajax section could please you make explicit how you linked the update_values function in show_cpu.html? – user11696358 Dec 01 '21 at 11:38
  • The `update_values` function is a javascript function executed when the html page loads in the browser. This html page is rendered by the `show_cpu` function. It will call the `/_stuff` endpoint using an Ajax request, that endpoint will respond with a JSON payload. Basically : User goes to `/show_cpu` which renders the html page containing the javascript snippet. This javascript snippet then proceeds to make an Ajax call to `/_stuff` periodically (using setInterval for example) which responds with json data we can parse and use as we please. – Depado Dec 07 '21 at 13:44