Jinja2,由Flask框架的创作者开发,是一款功能丰富的模板引擎,以其完整的Unicode支持、灵活性、高效性和安全性而备受推崇。最初受Django模板引擎启发,Jinja2为Flask提供了强大的模板支持,后来也成为其他项目的首选。在本文中,我们将深入探讨Jinja2的特性、语法以及如何在Flask应用中使用它来构建动态而又美观的Web页面。
IF语句用于在模板中执行条件判断,根据不同的条件呈现不同的内容。在模板中,通过{% if condition %} ... {% endif %}
的语法结构来定义条件块。其中,condition
是一个表达式或变量,如果该条件为真,模板引擎将执行if
块内的内容,否则将跳过。
IF模板语句支持多种条件判断,包括比较运算、逻辑运算等。通过合理运用IF语句,可以根据动态数据或用户输入,在页面上展示不同的信息或呈现不同的页面结构,从而实现更加灵活和个性化的页面设计。
// ----------------------------------------------
// 前端部分
// ----------------------------------------------
{% if username and username == "admin" %}
<h1>hello {{ username }} welcome</h1>
{% elif username and username == "lyshark" %}
<h1>hello {{ username }}</h1>
{% else %}
<h1>hello lyshark</h1>
{% endif %}
// ----------------------------------------------
// 后端部分
// ----------------------------------------------
@app.route("/", methods=["GET", "POST"])
def index():
return render_template("index.html",username = "admin")
FOR循环模板语句允许在模板中对数据进行迭代操作,便于遍历集合、列表或字典等数据结构,并在模板中对每个元素执行相同的操作。通过{% for item in iterable %} ... {% endfor %}
的语法结构,可以定义一个FOR循环块。
在FOR循环中,item
表示每次迭代中当前的元素,而iterable
则是要遍历的数据集合。循环块内的代码将在每次迭代时执行,允许动态生成页面内容。此外,Jinja2的FOR循环还支持循环索引、循环计数等功能,提供了灵活的迭代控制机制。
FOR模板语句在Web开发中经常用于动态生成页面元素,特别是在展示多条数据、列表或表格内容时非常实用。通过FOR循环,开发者可以更方便地处理和展示动态数据,提高页面的灵活性和交互性。
// ----------------------------------------------
// 前端部分
// ----------------------------------------------
<!--输出列表-->
{% for x in digits %}
<p>输出列表: {{ x }}</p>
{% endfor %}
<!--输出字典-->
{% for item in dicts %}
<!--第一个和最后一个元素-->
{% if loop.first %}
<b>第一个元素是: {{ item.name }}</b>
{% elif loop.last %}
<b>最后一个元素是: {{ item.name }}</b>
{% endif %}
<!--下标输出-->
<b>当前下标(从1开始): {{ loop.index }}</b>
<b>当前下标(从0开始): {{ loop.index0 }}</b>
<!--字典长度-->
<b>数组长度: {{ loop.length }}</b>
<b>迭代计数(从1开始): {{ loop.revindex }}</b>
<b>迭代计数(从0开始): {{ loop.revindex0 }}</b>
<p> 输出名字: {{ item.name }} 输出密码: {{ item.password }}</p>
{% endfor %}
<!--输出元组-->
{% for href,caption in tuples %}
<p>{{ href }} = {{ caption }}</p>
{% endfor %}
// ----------------------------------------------
// 后端部分
// ----------------------------------------------
@app.route("/", methods=["GET", "POST"])
def index():
return render_template("index.html",
digits=[1,2,3,4,5],
dicts=[
{'name':'John','password':'123123'},
{'name':'Tom', 'password':'123456'},
{'name':'Lisa', 'password':'123123'},
{'name':'Bob', 'password':'123456'}
],
tuples=[
('index.html', 'Index'),
('about.html', 'About'),
('downloads.html', 'Downloads')]
)
FOR模板排序允许在模板中对循环输出的元素进行排序或分组操作,通过内置的过滤器实现。这提供了更灵活的控制机制,使得模板能够按照特定的顺序展示数据,或者将数据按照某个条件分组呈现。
通过结合FOR循环和排序过滤器,模板可以根据开发者的需求对数据进行动态排列。在模板中,使用类似于{% for item in iterable | sort %} ... {% endfor %}
的语法,可以对iterable
中的元素进行排序。除了简单的字母和数字排序外,Jinja2还支持通过自定义函数进行排序,提供了更高度定制的排序功能。
// ----------------------------------------------
// 前端部分
// ----------------------------------------------
<!-- 按指定字段排序,这里设reverse为true使其按降序排 -->
<ul>
{% for item in dicts | sort(attribute='age', reverse=true) %}
<li> 名字: {{ item.name }} 年龄: {{ item.age }}</li>
{% endfor %}
</ul>
<!-- 列表分组,每组是一个子列表,组名就是分组项的值 -->
<ul>
{% for group in dicts|groupby('gender') %}
<li>组名: {{ group.grouper }}
<ul>
{% for user in group.list %}
<li>用户: {{ user.name }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
<!-- 取字典中的某一项组成列表,再将其连接起来 -->
<p>连接后: {{ dicts | map(attribute='name') | join(', ') }}</p>
<p>连接后: {{ dicts | map(attribute='age') | join(', ') }}</p>
// ----------------------------------------------
// 后端部分
// ----------------------------------------------
@app.route("/", methods=["GET", "POST"])
def index():
return render_template("index.html",
dicts = [
{'name':'Tom','gender':'M','age':20},
{'name':'John','gender':'M','age':18},
{'name':'Mary','gender':'F','age':24},
{'name':'Bob','gender':'M','age':31},
{'name':'Lisa','gender':'F','age':19}]
)
if __name__ == '__main__':
app.run(debug=True)
闪现机制是一种在请求之间传递信息的有效方式。它允许在一个请求中设置数据,然后在下一个请求中访问这些数据。主要通过flash()
函数实现,使开发者能够方便地在请求之间传递和呈现信息,增强了用户体验。
闪现机制通过flash()
函数实现,主要分为三种:
flash(message, category='message')
函数将消息闪现到下一个请求。这个消息可以是字符串,也可以是其他数据类型,而category
参数用于指定消息的类别,通常默认为'message'。category
参数,可以将消息划分为不同的类别,例如'error'、'success'等,以便在模板中有条件地处理这些消息。get_flashed_messages(with_categories=False, category_filter=['error', 'warning'])
函数获取所有闪现的消息。通过with_categories
参数可以选择获取消息时是否携带类别信息,而category_filter
参数则可以指定只获取特定类别的消息。这三种机制共同构成了Flask框架中灵活且强大的模板闪现系统,使得在Web应用中更便捷地实现消息传递和呈现。
1.模板中获取闪现信息,实现在下次请求时返回内容到前台。
<!--闪现消息,返回一个列表-->
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% if error %}
<p><strong>失败消息:</strong> {{ error }}</p>
{% endif %}
<form action="" method=post>
用户名: <input type=text name=username>
密码: <input type=password name=password>
<input type=submit value="用户登录">
</form>
后端只需要在验证通过的情况下,直接调用flash()
函数实现消息的前台传递。
from flask import Flask, flash, redirect, render_template, request, url_for
app = Flask(__name__, template_folder="./tempate",static_folder="./tempate")
app.secret_key = 'some_secret'
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == "POST":
if request.form['username'] != "lyshark" or request.form['password'] != "1233":
flash("登录失败了")
return render_template('index.html',error = "失败")
else:
flash("恭喜您登录成功")
return render_template('index.html')
if __name__ == "__main__":
app.run()
2.模板中的分类闪现,在闪现消息是指定一个消息分了i,如果不指定则默认分类为Message消息。
要使用自定义的分类,只要使用flash()
函数传入第二个参数即可。
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul>
{% for category, message in messages %}
<li class="{{ category }}">{{ category }}:{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
后端只需要增加第二个参数来指定需要显现的分组即可。
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == "POST":
if request.form['username'] != "lyshark" or request.form['password'] != "1233":
flash("登录失败了")
return render_template('index.html',error = "失败")
else:
flash("恭喜您登录成功","status")
flash("测试账户","username")
return render_template('index.html')
if __name__ == "__main__":
app.run()
3.模板中过滤闪现消息,过滤闪现即指在前台通过category_filter
增加过滤条件,来实现对特殊消息的过滤输出。
<!--闪现消息,增加过滤器-->
{% with messages = get_flashed_messages(category_filter=["username","status"]) %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% if error %}
<p><strong>失败消息:</strong> {{ error }}</p>
{% endif %}
<form action="" method=post>
用户名: <input type=text name=username>
密码: <input type=password name=password>
<input type=submit value="用户登录">
</form>
后端也可在闪现消息时指定一个category
属性实现过滤机制。
from flask import Flask, flash, redirect, render_template, request, get_flashed_messages
app = Flask(__name__, template_folder="./tempate",static_folder="./tempate")
app.secret_key = 'some_secret'
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == "POST":
if request.form['username'] != "lyshark" or request.form['password'] != "1233":
flash("登录失败了")
return render_template('index.html',error = "失败")
else:
flash("恭喜您登录成功","status")
flash("测试新的闪现",category="username") # 输出到username
flash("测试账户","username") # 闪现到username
print('闪现的信息是{}'.format(get_flashed_messages()))
return render_template('index.html')
if __name__ == "__main__":
app.run()
上下文是一个在请求处理过程中可以访问的全局对象集合。除了Flask本身提供的默认上下文之外,开发者还可以通过自定义上下文函数来添加额外的全局变量或函数,以便在视图函数和模板中使用。这就是自定义上下文函数的作用。
关键点和优势:
app.context_processor
装饰器定义的。这个函数会在每次请求处理前被调用,返回的字典中的键值对将成为全局变量。通过合理使用自定义上下文函数,可以使Flask应用更加灵活、可维护,并提供一致的全局信息和功能。这种机制有助于将一些通用的操作和数据注入到应用中,提高了代码的可读性和可重用性。
下面我们就来先定义一个上下文变量以及上下文函数,将返回字典的属性指向一个函数即可。
<p>当前APP名字: {{ app_name }}</p>
<p>当前时间戳: {{ local_time }}</p>
<p>当前名字: {{ local_user }}</p>
<p>当前时间: {{ current_time() }}</p>
<p>格式化输出: {{ current_time("%Y-%m-%d") }}</p>
<p> 传递整数调用函数: {{ add_function(34,12) }}</p>
<p> 传递数组调用函数: {{ list_function([1,2,3,4,5]) }}</p>
后端代码编写部分,需要引入current_app
然后在需要定义的函数上增加@app.context_processor
装饰器,返回参数通过字典调用dict(list_function = get)
得到结果。
from flask import Flask, render_template
from flask import current_app
import time
app = Flask(__name__)
# 自定义变量
@app.context_processor
def appinfo():
return dict(app_name = current_app.name,
local_time = time.time(),
local_user = "lyshark"
)
# 自定义函数
@app.context_processor
def app_function_gettime():
def get_time(timeFormat="%b %d, %Y - %H:%M:%S"):
return time.strftime(timeFormat)
return dict(current_time = get_time)
# 自定义函数(传递整数)
@app.context_processor
def app_function_add():
def get(x=0,y=0):
z = x + y
return z
return dict(add_function = get)
# 自定义函数(传递数组)
@app.context_processor
def app_function_list():
def get(x=[]):
sum = 0
for item in x:
sum = sum + item
return sum
return dict(list_function = get)
@app.route("/", methods=["GET", "POST"])
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run(debug=True)
自定义过滤器是一种强大的工具,允许开发者在模板中对数据进行各种处理和格式化操作。过滤器其实就是函数,通过使用add_template_filter
方法将自定义函数注册为模板过滤器,从而在模板中调用。
关键点和优势:
add_template_filter
方法将这个函数注册为模板过滤器。这个函数将用于对模板中的数据进行处理。通过灵活使用自定义过滤器,可以使模板引擎更加强大,满足更复杂的展示需求。这种机制有助于降低模板中的代码复杂度,提高开发效率,同时保持模板的可读性。
过滤器其实是一个函数,函数支持自定义功能,通过flask的add_template_filter
将我们的函数加入到过滤器表单中。
<p>输出双数: {{ [1,2,3,4,5,6,7,8,9,10] | double_step }}</p>
<p>输出子列表: {{ [1,2,3,4,5,6,7,8,9,10] | sub_step(1,5) }}</p>
<p>全局函数调用: {{ global_add(10,20,30) }} </p>
后台增加过滤器有两种方式,直接在函数上增加@app.template_filter('sub_step')
装饰器实现,或通过add_template_filter
将某个函数直接定义为过滤器使用。
from flask import Flask, render_template
from flask import current_app
app = Flask(__name__)
@app.route("/", methods=["GET", "POST"])
def index():
return render_template("index.html")
# 增加过滤器(方式1),输出列表中的双数
def double_step_filter(x):
return x[::2]
app.add_template_filter(double_step_filter,"double_step")
# 增加过滤器(方式2)
@app.template_filter('sub_step')
def sub(x, start, end):
return x[start:end]
# 增加全局函数
@app.template_global('global_add')
def function(x,y,z):
return x+y+z
if __name__ == '__main__':
app.run(debug=True)
自定义测试器是一种用于在模板中进行条件判断的工具。类似于过滤器,自定义测试器也是通过注册函数的方式来实现的,但是它们主要用于在模板中执行布尔条件测试。
关键点和优势:
@app.template_test()
装饰器将其注册为模板测试器。这个函数将包含一些布尔条件判断逻辑。通过合理使用自定义测试器,可以使得模板中的条件判断更为清晰和灵活。这种机制有助于降低模板中的代码复杂度,提高开发效率,同时使得模板的逻辑更易于理解和维护。
自定义测试器与过滤器基本一致,区别在于测试器使用@app.template_test()
装饰函数,其他方法与过滤器保持一致。
<!--验证字符串结尾是否是指定字符-->
{% if name is end_with "me" %}
<h2>"字符串 {{ name }}" 结尾是 "me"</h2>
{% else %}
<h2>"字符串 {{ name }}" 结尾不是 "me"</h2>
{% endif %}
<!--验证数组中是否有大于10的元素-->
{% if lists is array_of "10" %}
<h2>列表中存在,大于10的数据</h2>
{% endif %}
测试器后端分别定义两个函数,一个用于判断字符串结尾是否存在某个字符,另一个则是验证数组内是否存在大于元素。
from flask import Flask, render_template
app = Flask(__name__)
# 自定义测试器
@app.template_test('end_with')
def end_with(str,suffix):
return str.lower().endswith(suffix.lower())
# 自定义测试器(测试数组内是否有大于某值的)
@app.template_test('array_of')
def array_of(str,suffix):
for item in str:
if item >= int(suffix):
return True
@app.route("/", methods=["GET", "POST"])
def index():
return render_template("index.html",name = "lyshark me", lists = [1,2,3,4,5,6,7,8,56,33])
if __name__ == '__main__':
app.run(debug=True)