1 of 34

Jinja

2 of 34

  • The folks behind Flask are also the developers of a popular templating engine called Jinja.

  • The primary motivation for a templating engine like this is for us to be able to procedurally generate HTML based on the value of some variable(s) in our programs.

  • This allows us to mix Python and HTML!

3 of 34

  • Let’s build a simple web application to create a multiplication table, where the size of the table is determined by the user, and we generate the HTML for the table based on the size the user wants.

  • We will be making use of Flask’s render_template() method rather extensively in this application.

4 of 34

  • First, the basic app.

5 of 34

  • First, the basic app.

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route("/")

def mult_table():

6 of 34

  • Let’s start by just displaying a simple form to the user.

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route("/")

def mult_table():

7 of 34

  • Let’s start by just displaying a simple form to the user.

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route("/")

def mult_table():

return render_template("form.html")

8 of 34

  • By default, Flask will look in the templates/ directory to try to find a template with that name, so first we create that subdirectory, and then we toss a very simple form in there. (No Jinja in this one, since it’s static.)

9 of 34

<!DOCTYPE html>

<html>

<head>

<title>

Multiplication Table

</title>

</head>

<body>

<form action="/" method="post">

<input name="size" type="number" placeholder="dimension"/>

<input name="submit" type="submit" />

</form>

</body>

</html>

10 of 34

<!DOCTYPE html>

<html>

<head>

<title>

Multiplication Table

</title>

</head>

<body>

<form action="/" method="post">

<input name="size" type="number" placeholder="dimension"/>

<input name="submit" type="submit" />

</form>

</body>

</html>

11 of 34

<!DOCTYPE html>

<html>

<head>

<title>

Multiplication Table

</title>

</head>

<body>

<form action="/" method="post">

<input name="size" type="number" placeholder="dimension"/>

<input name="submit" type="submit" />

</form>

</body>

</html>

12 of 34

  • Okay, so now we’re good on displaying the form. But what about when the user submits the form? Right now, the form just keeps refreshing.

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route("/")

def mult_table():

return render_template("form.html")

13 of 34

  • Okay, so now we’re good on displaying the form. But what about when the user submits the form? Right now, the form just keeps refreshing.

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])

def mult_table():

return render_template("form.html")

14 of 34

  • Okay, so now we’re good on displaying the form. But what about when the user submits the form? Right now, the form just keeps refreshing.

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])

def mult_table():

if request.method == "GET":

return render_template("form.html")

15 of 34

  • Okay, so now we’re good on displaying the form. But what about when the user submits the form? Right now, the form just keeps refreshing.

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])

def mult_table():

if request.method == "GET":

return render_template("form.html")

# our form is set up to submit via POST

elif request.method == "POST":

return render_template("table.html")

16 of 34

  • Time to create another template. We know that HTML tables consist of <tr> tags for each row, consisting of a set of <td> tags for columns. So that lets us craft the super-basic idea for a template.

17 of 34

<!DOCTYPE html>

<html>

<head>

<title>Table</title>

</head>

<body>

<table>

<tr>

<td>

</td>

</tr>

</table>

</body>

</html>

18 of 34

  • Time to create another template. We know that HTML tables consist of <tr> tags for each row, consisting of a set of <td> tags for columns. So that lets us craft the super-basic idea for a template.

  • Next, we need to somehow convey to this template the number of rows the user supplied. We can do this by altering our call to render_template().

19 of 34

  • Okay, so now we’re good on displaying the form. But what about when the user submits the form? Right now, the form just keeps refreshing.

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])

def mult_table():

if request.method == "GET":

return render_template("form.html")

# our form is set up to submit via POST

elif request.method == "POST":

return render_template("table.html")

20 of 34

  • Okay, so now we’re good on displaying the form. But what about when the user submits the form? Right now, the form just keeps refreshing.

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])

def mult_table():

if request.method == "GET":

return render_template("form.html")

# our form is set up to submit via POST

elif request.method == "POST":

return render_template("table.html", dim=request.form.get("size"))

21 of 34

  • Okay, so now we’re good on displaying the form. But what about when the user submits the form? Right now, the form just keeps refreshing.

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])

def mult_table():

if request.method == "GET":

return render_template("form.html")

# our form is set up to submit via POST

elif request.method == "POST":

return render_template("table.html", dim=request.form.get("size"))

22 of 34

  • Time to create another template. We know that HTML tables consist of <tr> tags for each row, consisting of a set of <td> tags for columns. So that lets us craft the super-basic idea for a template.

  • Next, we need to somehow convey to this template the number of rows the user supplied. We can do this by altering our call to render_template().

  • Effectively, “dim” is now a variable within Jinja, and Jinja allows us to use a Python-like syntax interspersed within our HTML.

23 of 34

  • Jinja is introduced in the template in one of two ways:
    • {% ... %}
      • These delimiters indicate that what is between them is control-flow or logic.
    • {{ … }}
      • These delimiters indicate that what is between them should be evaluated and effectively “printed” as HTML.

  • Exactly what you can do with Jinja is an exercise for home, but its syntax is generally Python like, with a couple of quirks due to the way it is interspersed with HTML. Let’s see how we can use it to generate the HTML we need.

24 of 34

<!DOCTYPE html>

<html>

<head>

<title>Table</title>

</head>

<body>

<table>

<tr>

<td>

</td>

</tr>

</table>

</body>

</html>

25 of 34

<!DOCTYPE html>

<html>

<head>

<title>Table</title>

</head>

<body>

<table>

// loop to repeat “dim” times (“dim” # of rows)

<tr>

// loop to repeat “dim” times (“dim” # of columns)

<td>

// print out that value of the cell between <td>s

</td>

</tr>

</table>

</body>

</html>

26 of 34

<!DOCTYPE html>

<html>

<head>

<title>Table</title>

</head>

<body>

<table>

{% for i in range(dim) %}

<tr>

// loop to repeat “dim” times (“dim” # of columns)

<td>

// print out that value of the cell between <td>s

</td>

</tr>

{% endfor %}

</table>

</body>

</html>

27 of 34

<!DOCTYPE html>

<html>

<head>

<title>Table</title>

</head>

<body>

<table>

{% for i in range(dim) %}

<tr>

{% for j in range(dim) %}

<td>

// print out that value of the cell between <td>s

</td>

{% endfor %}

</tr>

{% endfor %}

</table>

</body>

</html>

28 of 34

<!DOCTYPE html>

<html>

<head>

<title>Table</title>

</head>

<body>

<table>

{% for i in range(dim) %}

<tr>

{% for j in range(dim) %}

<td>

{{ (i + 1) * (j + 1) }}

</td>

{% endfor %}

</tr>

{% endfor %}

</table>

</body>

</html>

29 of 34

<!DOCTYPE html>

<html>

<head>

<title>Table</title>

</head>

<body>

<table>

{% for i in range(dim) %}

<tr>

{% for j in range(dim) %}

<td>

{{ (i + 1) * (j + 1) }}

</td>

{% endfor %}

</tr>

{% endfor %}

</table>

</body>

</html>

30 of 34

<!DOCTYPE html>

<html>

<head>

<title>Table</title>

</head>

<body>

<table>

{% for i in range(dim|int) %}

<tr>

{% for j in range(dim|int) %}

<td>

{{ (i + 1) * (j + 1) }}

</td>

{% endfor %}

</tr>

{% endfor %}

</table>

</body>

</html>

31 of 34

<!DOCTYPE html>

<html>

<head>

<title>Table</title>

</head>

<body>

<table border=1>

{% for i in range(dim|int) %}

<tr>

{% for j in range(dim|int) %}

<td>

{{ (i + 1) * (j + 1) }}

</td>

{% endfor %}

</tr>

{% endfor %}

</table>

</body>

</html>

32 of 34

33 of 34

34 of 34

It may not look beautiful… but that’s what CSS is for!