BlackA,Talk is cheap,Show me the code.
我们在上一节中学习了Jinja2模板引擎的基本用法,并用Jinja2模板生成了一些简单的HTML页面。但是Jinja2的强大功能不止于此,这一节中我们将会继续学习Jinja2中的控制语句。
Jinja2提供了类似Python语法的 if 语句,用来控制渲染模板的哪一部分,这有点像C语言中的条件编译,但是远比条件编译的功能强大。我们先来看一个例子,在这个例子中,我们仿照V2EX的登录功能,当用户未登录时,在浏览器的右上角显示 “首页”、“注册”、和 ”登录“ 三个按钮,当用户登录后,显示 “首页”、“用户名”、”设置“、和 “登出” 四个按钮:
这次我们先来看看Python程序代码:
from flask import Flask,render_template app = Flask(__name__) # 因为我们还没有学习cookie,所以这里使用is_login来模拟用户是否登录 # 当is_login的值为1时,代表已经登录,为0代表未登录 @app.route("/<int:is_login>/") def index(is_login): if is_login == 1: # 如果用户已经登录,得到用户对应的信息,并传给模板渲染 # 因为我们还没有学习数据库操作,所以这里只使用固定的值来渲染模板 user = {"username" : "blacka","age" : 18} return render_template("index.html",user = user) else: # 如果用户没有登录,则仅仅渲染模板而不传递用户的信息 return render_template("index.html") if __name__ == "__main__": app.run(debug = True)
在上面这个程序中,我们先确定用户是否登录,如果用户已经登录,我们就从数据库中查询对应的用户信息,并把用户信息传递给模板进行渲染;如果用户没有登录,我们就什么也不传递,直接渲染模板,这就要我们的模板可以判断flask程序是否传递了需要渲染的用户信息,即user这个字段值是否为空,如果为空就说明用户没有登录,显示 “首页”、“注册”、和 ”登录“ 三个按钮,反之说明用户已经登录,显示 “首页”、“用户名”、”设置“、和 “登出” 四个按钮:
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <title>Hello</title> </head> <body> {# if 语句使用一个大括号和一个井号扩起 #} {% if user %} {# 如果定义了user这个变量就渲染这里 #} <a href="#">首页</a> <a href="#">{{user.username}}</a> <a href="#">设置</a> <a href="#">登出</a> {% else %} {# 如果没有定义就渲染这里 #} <a href="#">首页</a> <a href="#">注册</a> <a href="#">登录</a> {# 使用endif来标识if语句块的结束 #} {% endif %} </body> </html>
下面是这个程序的运行结果:
提供上面这个例子我们可以看出 if 语句的一般语法格式:
{% if 条件1 %} 语句块1 [ {% elif 条件2 %} ] [ 语句块2 ] ... [ {% else %} ] [ 语句块3 ] {% endif %}
在Jinja2中控制语句(if、for)使用 ”{%“ 和 ”%}“ 括起来,由 ”[“ 和 "]"括起来的部分代表是可选的,因为HTML会忽略源文件中的空白,所以无法使用缩进来确定 if 语句的结尾,需要使用 “{% endif %}” 表示 if 语句的结尾。
if 后面的条件可以写类似Python的条件表达式,具体的细节可以参考官方文档。
Jinja2不仅仅提供了 if 语句用来控制条件,还提供了 for 语句用来循环的渲染某一个语句,当我们需要动态的生成一个列表或者表格的时候,使用 for 循环可以化简我们的工作量:
# 当用户访问/books/时在浏览器上显示书籍信息的列表 from flask import Flask,render_template app = Flask(__name__) @app.route("/books/") def show_books(): # 一个字典列表存放书籍 books = [ { "姓名" : "红楼梦", "作者" : "曹雪芹", "价格" : 109 }, { "姓名" : "三国演义", "作者" : "罗贯中", "价格" : 120 }, { "姓名" : "水浒传", "作者" : "施耐庵", "价格" : 119 }, { "姓名" : "西游记", "作者" : "吴承恩", "价格" : 108 } ] # 传递字典列表给Jinja2框架 return render_template("books.html",books = books) if __name__ == "__main__": app.run(debug = True)
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <title>书籍信息</title> </head> <body> <!-- 无序列表 --> <ul> {# 循环遍历列表,语法格式与python类似 #} {% for book in books %} <!-- 列表项 --> <li> {# 循环遍历字典,除了items()方法外, #} {# 还可以使用keys()、values()、 #} {# iteritems()、iterkeys()等字典方法 #} {% for k,v in book.items() %} {{k}} : {{v}} {% endfor %} </li> {% endfor%} </ul> </body> </html>
这个例子虽然有些臃肿,但是它展示如何使用for 循环遍历列表和字典,下面是代码的运行效果:
另外,Jinja2还内置了一些循环变量,可以在循环中访问它们:
# loop.index 当前循环迭代的次数(从 1 开始) # loop.index0 当前循环迭代的次数(从 0 开始) # loop.revindex 到循环结束需要迭代的次数(从 1 开始) # loop.revindex0 到循环结束需要迭代的次数(从 0 开始) # loop.first 如果是第一次迭代,为 True 。 # loop.last 如果是最后一次迭代,为 True 。 # loop.length 序列中的项目数。 # loop.cycle 在一串序列间期取值的辅助函数。
我们可以通过 loop.first 变量实现书籍名字的黑体:
{% for k,v in book.items() %} {% if loop.first %} <b> {{k}} : {{v}} </b> {% else %} {{k}} : {{v}} {% endif %} {% endfor %}
*** 最后,根据官方文档的建议,应在模板中尽量少的使用if 和 for 等控制语句。 ***