Day 7 jinja (2)

前言

今天要继续看 jinja 的使用,昨天的内容比较接近一般的变数存取、if、for 的使用,而今天的内容则是类似自定义函数。

范例

先来看个范例。请注意 index.htmlmsg.jinja 都要放在昨天提到的 templates/ 里面。

app.py

from flask import Flask, render_template, flash

app = Flask(__name__)

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


app.config["SECRET_KEY"] = "rc498mt6848"
app.run(host="127.0.0.1", port=8080, debug=True)

index.html

{% from 'msg.jinja' import display_msg %}

<!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>
    {{ display_msg(get_flashed_messages(with_categories=True)) }}
    <h1>User list</h1>
    <ul>
        {% for user in users %}
        <li>{{ user }} ({{ loop.index }})</li>
        {% endfor %}
    </ul>
</body>
</html>

msg.jinja

{% macro display_msg(messages) %}
<div id="messages">
    {% if messages %}
    {% for category, message in messages %}
        <div class="{{ category }}">
            <span>{{ message }}</span>
        </div>
    {% endfor %}
    {% endif %}
</div>
{% endmacro %}

这次的档案比较多,也比较繁杂,我们一个一个慢慢看。

app.py 基本上就是昨天用来解释 for 的范例,但是新加入了一个叫做 flash 的函式 ,它的用途是把後端的资料送到前端显示。比如说可能使用者在注册帐号的时候,使用者名称已经被用过了,那後端就可以发一条警告讯息到前端通知使用者这个名称被使用了。虽然这里说是前端,但基本上它也是由 jinja 去跑的,所以需要用 render_template。在他的後面我们加了一个 category 的参数,这是选用,它的功能就是放一个标签给这条讯息,让前端可以因应,例如说上面的名称已被使用可能就是 warning,而注册成功可能就是 success 之类的,在下面我们会用到它。

这里还有一个需要注意的是,有一行 app.config["SECRET_KEY"] = "rc498mt6848"app.config 是这个 app 的设定档,未来会有更舒服的方式去设定他,而 SECRET_KEY 是这个 app 的 secret key,会用来帮忙处理一些 session 的东西,像是此处的 flash、登入的 session、未来会提到的 csrf_token 等等都会用到它,而有了它也可以反推前述的东西,因此不能外流,此处只是随便乱打,而且在开发模式,所以是没有关系的。

如果你在思考这个 flash 的东西到底去哪里了,可以看看 session,但一样要记得先 import (from flask import session)。应该可以看到类似 <SecureCookieSession {'_flashes': [('meow', 'meow')]}> 的内容。这个讯息还有一个特性是,在被前端使用过之後就会自动从 session 中消失,所以同样的讯息不会一直卡着。

接下来看到 index.html,他在最一开始就 import,但是这并不是 python 的 import,他 import 的是一个 jinja 的档案,而这个档案在下方,我们等等就会看到。在 body 里面,我们呼叫刚刚引入的 display_msg,并将 get_flashed_messages(with_categories=True) 作为其引数。这个函式就是用来抓 session 里面有哪些 flash 的讯息,後面的 with_categories 是说明要不要加上 category,预设是 False。他的表示方式是一个 list,以此处为例,有 with_categories=True 的结果会是 [("cat", "meow")]、没有打或是设为 False 会得到 ["meow"]

最後看到 msg.jinja,他就像是一个 module,里面有一个函式可以给别人引入。首先,就如同 if 和 for,他也需要 endmacro,接下来我们可以看到他在 jinja 里面跑着非常接近 python 的语法,也可以发现刚刚设定的 category 被当成 class 来用。

set & with

在前面讲存取变数的时候,可能有人会好奇我们该如何设变数,因为之後用不太到,所以没有放在前面讲,我自己觉得不太会用到的原因是因为我们会用到的变数都已经在 render_template 中设定好了,剩下可能会用到的变数大概也只是 for 的时候会用到的区域变数,所以我个人觉得这个部分不太会使用,等等也不会放上范例。但我自己也真的有用过,像是想要把一些设定档交给 jinja 去对照,那就会先把设定档 import 进模板 (如何 import 等等会提到),然後给他一个变数名称作为简写之类的。

标题写着 set & with,代表这里有两种设定变数的方式,差异只在是全域变数还是区域变数而已。我们分开来说。

  • set 的用法是 {% set var=value %},非常简单。
  • with 就比较麻烦一点,他建立了一个 scope,也就是说他创造的是区域变数。他的用法是 {% with var=value %},但在这个 scope 结束的时候要 {% endwith %},和前面提到的类似。

import

虽然我们是在 python 里面用 jinja,但是在 jinja 中我们无法使用 python 的函式库。如果真的要使用的话,我们需要一点小技巧。但我自己是认为,能不要用就不要用。

python 里面有一个套件叫做 importlib,我们可以在 render_template 後面加上 IMPORT=importlib.import_module (import 在 jinja 里面是保留字,所以不能用),然後在模板里面就可以 set var=IMPORT('module'),照着正常该怎麽用就可以了。

References

Configuration Handling - SECRET_KEY
How does the 'with' statement work in Flask (Jinja2)?
Whare are the difference between set and with in jinja
Import a Python module into a Jinja template?


<<:  [Day4] Android - Kotlin笔记:RecyclerView Adapter - ListAdapter + DiffUtil

>>:  30天轻松学会unity自制游戏-了解动画系统

[Day 22] 阿嬷都看得懂的元素容器与隐藏空格解法

阿嬷都看得懂的元素容器与隐藏空格解法 昨天我们做出了满版横幅的粉红贴纸,今天要开始切中央的橘色贴纸与...

Day 18:Kotlin 过滤(filter)集合资料用法

本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...

Git

最初,Linux Kernel 的社群采用压缩档或是补丁的方式进行维护工作。一直到 2002 年,开...

Day19-部署篇(一)Amazon EC2

大家好~ 接下来要把我们的 Echo bot 部署上 Amazon EC2 啦~ Amazon EC...

我想推荐的WordPress主题,2020黑色星期五折扣开跑

在我的架站经验中,我始终在「想要的功能与样式」和「网页载入速度」中不断拉扯! 不过,这样也好,促使我...