iT邦幫忙

2021 iThome 鐵人賽

DAY 6
0
Modern Web

Flask系列 第 6

Day 6 jinja (1)

前言

今天要來看 jinja 這個模板引擎。簡單來說,它的功能就是在 HTML 裡面執行一般程式,等等看過範例之後應該可以更清楚它的作用。

雖然說是在執行一般程式,但是其語法和一般程式也有一些些差別,我自己的習慣是照著一般程式的語法,如果錯了的話再去搜尋正確的用法。

前置作業

這次並非只需要簡單地把程式碼複製到 app.py 而已,我們需要先建立一個名為 templates 的資料夾,名字必須完全符合,等等會需要把 HTML 及以後會用到的 jinja 模板放在裡面。

範例一

建立完資料夾後,我們來看看以下這份程式碼,請注意 index.html 需要放在 templates 目錄內。

app.py


from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def index_page():
    name = "cat"
    return render_template("index.html", username=name)


app.run(host="127.0.0.1", port=8080, debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Index</title>
</head>
<body>
    {{ username }}
</body>
</html>

app.py 中,我們看到了一個新的函式:render_template,不例外地,他也需要 import。它的功用是把一個 template 送入 jinja 跑,然後就可以得到一個字串,內容就是跑出來的 HTML,最後會把他 return 回去,這樣一來,使用者就可以收到一個漂亮的 HTML,而非之前連 head 都沒有的單純內容。有了它的好處是,我們不需要把超長的 HTML 放在 python 檔案裡面,而且可以用比較漂亮的方式生出 HTML,等等在看 for 迴圈的時候會更有感覺。

它需要一個 template name,以此處為例就是 index.html。接下來會看到他後面的 username=name,他會把剛剛定義的 name 傳入 template 給 jinja 處理,而在 jinja 裡面,他的名字叫做 username。接著我們看到 index.html,它裡面有一行 {{ username }},在 jinja 裡面,我們使用大括號來表示我們存取的變數,此處就是剛剛在 redner_template 傳入的 name

這邊值得注意的是,jinja 只會去處理大括號的部分,其他 HTML 的元素他秋毫無犯,會原汁原味秀出來。

範例二

剛剛看了基本的使用方法,現在來看看 if 要怎麼處理。

app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def index_page():
    state = "running"
    return render_template("index.html", state=state)


app.run(host="127.0.0.1", port=8080, debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Index</title>
</head>
<body>
    {% if state == "running" %}
    <p>running</p>
    {% else %}
    <p>terminated</p>
    {% endif %}
</body>
</html>

我們這次傳入了 state 這個變數,然後在 jinja 裡面判斷他是否等於 running。這裡要注意的是他 if 並不是跟剛剛一樣用兩個大括號,而是一個大括號和一個百分符號。這兩種的差別在於他是不是一個 statement,{% %} 是給 statement 用的,而 {{ }} 則是用來存取內容用的。還有跟 python 不太一樣的是他有 endif,要記得加。也因為他已經有了 endif,所以他不會管你的縮排。

還有一個要注意的是,我們的 <p>running</p><p>terminated</p> 並沒有加上大括號,因為他就是一般的 HTML element。如果要把 running 換成 state,那就要改成 <p>{{ state }}</p>

範例三

接下來就要講迴圈,比較特別的是 jinja 只有 for 沒有 while,以下是一個範例。

app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def index_page():
    users = ["Mary", "Cat", "Meow", "Harry"]
    return render_template("index.html", users=users)


app.run(host="127.0.0.1", port=8080, debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Index</title>
</head>
<body>
    <h1>User list</h1>
    <ul>
        {% for user in users %}
        <li>{{ user | upper }} ({{ loop.index }})</li>
        {% endfor %}
    </ul>
</body>
</html>

在這個範例中我們傳入了一個叫做 users 的 list,接下來我們交給 jinja 處理,他幫我們跑一個 for 迴圈 (注意他也是 statement,所以要用 {% %}),依序把 users 裡的 user 取出來,然後放在 li 裡面。接下來看到後面的 loop.index,他是一個預設就存在的變數,他表示了平常在 list 看到的 index,但他是從 1 開始數,如果要從零開始數需要用 loop.index0

最後看到在 user 後面的 | upper,他是一個 filter,就是等同於平常用到的 str.upper(),只是在此處我們習慣使用 filter。在此處當然可以直接 {{ user.upper() }} 就好,但是有些時候沒有辦法用 python 的語法來處理,像是如果我們直接使用 int(),他會告訴我們 undefined,這時候就需要用 | int 來達成需求。

如果想要加入自定義的 filter 的話,flask 已經有一個包裝好的方法可以處理,以下是範例。

app.py

from flask import Flask, render_template
app = Flask(__name__)

@app.template_filter()
def get_initial(s):
    return s[0]

@app.route("/")
def index_page():
    user = "Cat"
    return render_template("index.html", user=user)


app.run(host="127.0.0.1", port=8080, debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Index</title>
</head>
<body>
    {{ user | get_initial }}
</body>
</html>

可以看到在 app.py 的最前面我們使用了 app.template_filter,讓他裝飾了一個會丟出第一個字母的函式,接下來在 index.html 我們就直接使用了這個 filter,不需要把它當成參數放在 render_template,也不需要特別 import,他就直接變成了預設就存在的 filter。

References

Basic Syntax of Jinja
Python jinja2 + flask
Custom Jinja template filters in Flask


上一篇
Day 5 基本 flask 函式 (2)
下一篇
Day 7 jinja (2)
系列文
Flask30

尚未有邦友留言

立即登入留言