Flask is a micro web framework which is really fun to use. With the following snippet You have a complete web app working within seconds.
from flask import Flask # 1 app = Flask(__name__) # 2 @app.route('/') # 3 def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run() #4
All this snippet does is
- Importing the Flask module,
- Creating the app,
- Defining an so called endpoint and finally
- Running the web app in a container.
Flask brings its own WSGI server called “werkzeug”. Please use it just for development purposes. It is not suitable for live applications.
Rendering a Template
Because the days of writing HTML as strings in a servlet are over, Flask comes with a template language called “Jinja2”. We replace the line
return 'Hello World!'
with the render_template function and pass a template and the message into the function:
from flask import render_template ... @app.route('/') def hello_world(): hello_string = "Hello World" return render_template("index.html", hello_message=hello_string)
Jinja2 uses curly brackets to identify their template code blocks.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ hello_message }} </body> </html>
{{ hello_message }} # is equivalent to {% print hello_message %}
So if You want to show a list on your page containing your favorite fruits You can fetch a list of fruits from the server and let the template engine replace the markup with the data before handing the rendered page to the browser. We use a simple list for demonstration.
@app.route('/static_item_list') def static_item_list(): fruits = ["Apple", "Banana", "Lemon"] return render_template("static_item_list.html", fruits=fruits)
<table> <thead> <tr> <th>Fruit</th> </tr> </thead> <tbody> {% for fruit in fruits %} <tr> <td>{{ fruit }}</td> </tr> {% endfor %} </tbody> </table>
Bringing AJAX to Flask
When we wanted to filter a list back in the old days, we had to do a complete roundtrip by sending a POST with parameters to the server, waiting for the response and rendering a new page. Ugh! In Flask it looks like this:
<form method="POST"> <table> <thead> <tr> <th>Fruit</th> </tr> <tr> <td> <input name="filter"/> <button>Search</button> </td> </tr> </thead> <tbody> {% for fruit in fruits %} <tr> <td>{{ fruit }}</td> </tr> {% endfor %} </tbody> </table> </form>
@app.route('/item_list_with_filter', methods=["GET", "POST"]) def item_list_with_filter(): fruits = ["Apple", "Banana", "Lemon"] if "filter" in request.form: fruit_filter_value = request.form["filter"] else: fruit_filter_value = "" filtered_items = [] for fruit in fruits: if fruit_filter_value.lower() in fruit.lower(): filtered_items.append(fruit) return render_template("item_list_with_filter.html", fruits=filtered_items)
Nowadays You can just refresh those parts of a site where the data should be updated. I will demonstrate this with some jQuery functionality, but You can do it as well in plain old vanilla JavaScript.
This is the udpated HTML page. Please note that the table body is empty and does not contain template language code.
<table id="items"> <thead> <tr> <th>Fruit</th> </tr> <tr> <td> <input id="filter"/> </td> </tr> </thead> <tbody></tbody> </table>
First of all we bind a keyup event to the filter input. To ensure that the complete page is already loaded, we do it in the document-ready function:
$(document).ready(function(){ ... $("#filter").keyup(get_table_data); ... });
To fetch data from the server we use the getJSON-function.
$.getJSON( url, [data], [callback] )
This function is a shortcut for
$.ajax({ dataType: "json", url: url, data: data, success: success });
As URL we have to provide an endpoint that accepts GET requests, as data we give the value from the input field and last but not least as callback a function that will use the data from the response to update the table.
function get_table_data(){ $.getJSON('/_items', { filter: $("#filter").val() }, function(data){update_table.call(this, data)} ) }
Let’s have a look at the before mentioned endpoint:
@app.route('/_items') def items(): filter_value = request.args.get('filter', "", type=str) fruits = ["Apple", "Banana", "Lemon"] filtered_items = [] for fruit in fruits: if filter_value.lower() in fruit.lower(): filtered_items.append(fruit) return jsonify(fruits=filtered_items)
There are two interesting parts here: To get the arguments from the request we use
request.args.get()
The get method takes the argument name, a default value and a type. Instead of returning a rendered template we use the method
jsonify()
That’s all it takes to get JSON data from a Flask application. The missing piece is the function which alters the content on the client side after receiving the data. It looks like this
function update_table (data) { var $tbody = $("#items").find("tbody"); $tbody.empty(); var rows = data.fruits.length; for (var i = 0; i < rows; i++) { var row = "<tr><td>" + data.fruits[i] + "</td></tr>"; $tbody.append(row); } }
This function clears the body of the table via empty(), iterates over the data and appends the new rows to the table body. and Bob’s your uncle!