flask 使用 jinjia2 模板引擎,为了便于使用,已经集成到 render_template 函数中,可以直接调用。模板引擎实现对模板的渲染,就是根据上下文,对模板中的占位变量,用真实值替换,形成最终的响应文件。
默认情况下,Flask 在程序文件夹中的 templates 子文件夹中寻找模板。
(一)模板的调用
demo.py文件代码如下:
from flask import Flask from flask import render_template app = Flask(__name__) @app.route('/') def index(): return render_template("index.html")
注意:render_template中是包含 .html 后缀的完整文件名
index.html文件代码如下:
hello world!
执行demo.py后,浏览器访问地址:http://127.0.0.1:5000/,页面显示“hello world”。
这就完成了简单的一次模板调用。
(二)模板的传参
#模板传参 @app.route('/user/') def user(xiao): return render_template("xiao.html",xiao=xiao)
第一个参数是模板的名称,然后是 键/值 对,xiao=xiao
左边表示模板中的占位符,右边是当前视图中的变量。意思是,将当前视图中变量xiao
的值,赋值给模板中名为xiao
的占位符,用于渲染。
xiao.html代码如下:
传递参数:{{ xiao }}
执行后,浏览器访问地址:http://127.0.0.1:5000/user/
若是:http://127.0.0.1:5000/user/123,则显示“传递参数:123”
若是:http://127.0.0.1:5000/user/abc,则显示“传递参数:abc”
(三)模板的变量传参
@app.route('/test') def hello_world(): centent="调用的hello_world()函数里面的centent" return render_template("test.html",centent=centent)
第一个参数是模板的名称,然后是 键/值 对,centent=centent
左边表示模板中的占位符,右边是当前视图中的变量。意思是,将当前视图中变量centent
的值,赋值给模板中名为centent
的占位符,用于渲染。
test.html代码如下:
调用的参数为: {{ centent }}
执行后,浏览器访问地址:http://127.0.0.1:5000/user/test,返回结果为:"调用的参数为: 调用的hello_world()函数里面的centent"
- 表示
{{ name }}
占位符,告诉模板引擎,这个位置的值从渲染模板时传递的数据字典中获取
- 支持的变量类型
支持所有类型,字符串、整型、列表、字典 ......
- 修改显示样式
通过使用过滤器,可以定制 变量的值 显示的效果,比如 大小写。{{ name | 过滤器 }}
过滤器列表
- 模板变量
在模板中设置模板变量
{% set name = 'john' %}
(四)模板的相对复杂的对象传递
Jinja2变量过滤器
过滤器名 | 说 明 |
safe | 渲染值时不转义 |
capitalize | 把值得首字母转为大写,其它字母转为小写 |
lower | 把值转换成小写形式 |
upper | 把值转换成大写形式 |
title | 把值中每个单词的首字母转换成大写 |
trim | 把值得首尾空格去掉 |
striptags | 渲染之前把值中所有的HTML标签都删掉 |
safe 过滤器值得特别说明一下。默认情况下,出于安全考虑,Jinja2 会转义所有变量。例
如,如果一个变量的值为 '
Hello
' ,Jinja2 会将其渲染成 '<h1>Hello</h1>' ,浏览器能显示这个 h1 元素,但不会进行解释。很多情况下需要显示变量中存储
的 HTML 代码,这时就可使用 safe 过滤器。
千万别在不可信的值上使用 safe 过滤器,例如用户在表单中输入的文本。
完整的过滤器列表可在 Jinja2 文档(http://jinja.pocoo.org/docs/templates/#builtin-filters)中
查看。
新建modes.py文件,代码如下:
#创建一个User类,用来存放users class User(object): #定义两个字段,一个user_id,一个user_name def __init__(self,user_id,user_name): self.user_id=user_id self.user_name=user_name
demo.py文件代码如下:
#coding:utf-8 from flask import Flask from flask import render_template from modes import User app = Flask(__name__) #传递一个name对象 @app.route('/name') def name(): user=User(1,"xiaojingjing") return render_template("user_index.html",user=user) if __name__ == '__main__': app.run()
user_index.html文件代码如下:
你好! {{ user.user_name }}
执行后,浏览器访问地址:http://127.0.0.1:5000/name,返回结果为:"你好! xiaojingjing"
(五)控制语句 if else 判断
demo.py文件代码如下:
#控制语句,if else 判断 @app.route('/user_name/') def user_name(user_id): user=None if int(user_id)==1: user=User(1,'xiaojingjing') # else: # return "Sorry,no this user" return render_template("user_id.html",user=user)
user_id.html文件代码如下:
{% if user %} 你好,{{ user.user_name }}! {% else %} no this user {% endif %}
执行后,浏览器访问地址:http://127.0.0.1:5000/user_name/1,返回结果为:"你好! xiaojingjing"
执行后,若浏览器访问地址:http://127.0.0.1:5000/user_name/2,返回结果为:"no this user"
(六)控制语句 for循环
demo.py文件代码如下:
#控制语句,for循环 @app.route('/user_list') def user_list(): users=[] for i in range(1,11): user=User(i,"小白"+str(i)) users.append(user) return render_template("user_list.html",users=users)
user_list.html文件代码如下:
{% for user in users %} {{ user.user_id }}--{{ user.user_name }}
{% endfor %}
执行后,浏览器访问地址:http://127.0.0.1:5000/user_list,
返回结果为:
"1--小白1 2--小白2 3--小白3 4--小白4 5--小白5 6--小白6 7--小白7 8--小白8 9--小白9 10--小白10"
(七)继承
如果多个页面的大部分内容相同,可以定义一个母模板,包含相同的内容,然后子模板继承内容,并根据需要进行部分修改
base.html
,母模板,其中,用{% block title %}...{% endblock %}
定义了可以由子模板替换的区域,title
是区块的名称,可以有多个区块
{% block title %}Hello{% endblock %}
在子模板中,声明继承的母模板,然后用{% block title %}...{% endblock %}
指定替换哪个区块的内容,并填入自己的内容。子模板中没有指定的区块,默认使用母模板的内容
{% extends "base.html" %} {% block title %}john{% endblock %}
如果希望能够保留母版的内容,并添加新内容,可以使用super()
{% extends "base.html" %} {% block title %} {{ super() }} john {% endblock %}
PS:模板里面,不能同时有两个{% extends " " %}
语句,即使另一个被注释了也不行
如果多个网页中都有一段内容相同,可以将相同的内容放入一个文件中comments.html
,通过include
导入
{% include 'comments.html' %}
首先,创建一个基类
base.html文件,代码如下:
{% block content %} {% endblock %}top部分
底部部分
one_base.html文件,代码如下:
{% extends "base.html" %} {% block content%} 这是第一页 {% endblock %}
two_base.html文件,代码如下:
{% extends "base.html" %} {% block content%} 这是第二页 {% endblock %}
然后到demo再新定义两个路由,代码如下:
#模板的继承 @app.route('/one_base') def one_base(): return render_template("one_base.html") @app.route('/two_base') def two_base(): return render_template("two_base.html")
执行后,浏览器访问地址:“http://127.0.0.1:5000/one_base” 和“http://127.0.0.1:5000/two_base”
--------------待补充:
宏:macro...endmacro
类似函数
定义一个宏,指定宏的名称、参数,调用
{% macro x(y) %} ... {% endmacro %} {{ x(y) }}
如果需要在多个模板中复用,可以将宏的定义放入一个文件,‘macro.html’
{% macro x(y) %} ... {% endmacro %}
然后导入使用
import 'macro.html' as macro {{ macro.x(y) }}
bootstrap
Bootstrap是 Twitter 开发的一个开源框架,它提供的用户界面组件可用于创建整洁且具有吸引力的网页,而且这些网页还能兼容所有现代 Web 浏览器。
一个名为Flask-Bootstrap
的 Flask 扩展, 可以简化在程序中集成 Bootstrap 的过程。
安装:
pip install flask-bootstrap
初始化
从 flask.ext 命名空间中导入,然后把 程序实例传入构造方法进行初始化。
run.py
from flask.ext.bootstrap import Bootstrap # ... bootstrap = Bootstrap(app)
初始化 Flask-Bootstrap 之后,就可以在程序中使用一个包含所有 Bootstrap 文件的基模板。 这个模板利用 Jinja2 的模板继承机制,让程序扩展一个具有基本页面结构的基模板,其中 就有用来引入 Bootstrap 的元素。
{% extends "bootstrap/base.html" %} {% block title %}Flasky{% endblock %} {% block navbar %} {% endblock %} {% block content %}{% endblock %}Hello, {{ name }}!
Jinja2 中 的 extends 指 令 从 Flask-Bootstrap 目录中导入 bootstrap/base.html, 从而实现模板继承。Flask-Bootstrap 中的基模板提供了一个网页框架,引入了 Bootstrap 中的所有 CSS 和 JavaScript 文件
virtualenv 环境中,目录为lib/python2.7/site-packages/flask_bootstrap/templates/bootstrap/
基模板中定义了可在衍生模板中重定义的块。block 和 endblock 指令定义的块中的内容可添加到基模板中。
Bootstrap 官方文档是很好的学习资源,有很多可以直接复制粘贴的示例。
自定义错误页面
像常规路由一样,Flask 允许程序使用基于模板的自定义错误页面。最常见的错误代码有两个:404,客户端请求未知页面或路由时显示;500,有未处理的异常时显示。
自定义错误页面,代码如下:
@app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404
和视图函数一样,错误处理程序也会返回响应。它们还返回与该错误对应的数字状态码。 返回指定的数字状态码似乎没有什么用
url_for 生成连接
模板中可能有去往多个不同页面的链接,例如导航条。
在模板中直接编写简单路由的 URL 链接不难,但对于包含可变部分的动态路由,在模板中构建正确的 URL 就很困难。而且,直接编写 URL 会对代码中定义的路由产生不必要的 依赖关系(hardcode)。如果修改 路由、视图 的绑定关系, 模板中的链接可能会失效。
为了避免这些问题,Flask 提供了url_for()
辅助函数,它可以使用程序URL映射
中保存的信息,根据视图名称生成 URL。
例如,对于下面的视图
@app.route('/') def index(): return 'Hello World!
'
调用 url_ for('index')得到的结果是/
。调用url_for('index', _external=True)返回的则是绝对地址,是http://localhost:5000/
。
在程序内(模板、视图中)生成连接程序内不同路由的链接时,使用相对地址
就足够了,浏览器、程序能够根据当前的 URL 补全。但如果要在浏览器以外生成链接,例如在确认邮件中的链接,则必须使用绝对地址
,否则谁也不知道前缀是什么。
使用url_for()
生成链接时,将动态部分作为关键字参数
传入。例如,
@app.route('/user/') def user(name): return render_template('user.html', name=name)
url_for ('user', name='john', _external=True)
返回结果是:http://localhost:5000/user/john
默认 _external 为 False,表示生成相对路径;为 True 时,表示生成绝对路径
函数能将任何额外参数
添加到查询字符串
中。例如,
url_for('user', name='john', page=2)
的返回结果是/user/john/?page=2
对于多层的模板结构,render_template 函数中需要添加从templates
目录下文件夹开始的路径信息,render_template('main/index.html')
,结构为templates/main/index.html
,url_for() 需要用.
隔开目录,url_for('main.index.html')
。