跟着学习:http://www.pythondoc.com/flask-mega-tutorial/templates.html
回顾上一章:https://mp.youkuaiyun.com/mdeditor/85001432#
本章内容
- 模板从天而降
- Jinja2引擎
- 回到我们的工程文件
模板从天而降
如果你能够保持你的应用程序与网页的布局或者界面逻辑上是分开的,这样不是显得更加容易组织?难道你不觉得是这样吗?你甚至可以聘请一个网页设计师来设计一个杀手级的网页而你专注于 Python 编码。模板可以帮助实现这种分离。
模板是包含响应文本的文件,其中包含用占位变量表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为渲染。为了渲染模板,flask使用一个名为Jinja2的强大模板引擎!
简单展现以下Jinja2模板,动态内容在 {{ … }} 中。
文件:app/templates/index.html
<html>
<head>
<title>{{ title }} - microblog</title>
</head>
<body>
<h1>Hi, {{ user.username }}!</h1>
{% for post in posts %}
<div><p>{{ post.author.username }} says: <b>{{ post.body }}</b></p></div>
{% endfor %}
</body>
</html>
现在看看怎样在我们的视图函数中渲染模板
flask提供的render_template()函数把Jinja2模板引擎集成到了应用中,这个函数的第一个参数时模板的文件名,随后的参数都是键-值对,表示模板中变量对应的具体值。
文件app/routes.py
@app.route('/')
@app.route('/index')
def index():
user = {'username': 'Miguel'}
posts = [
{
'author': {'username': 'John'},
'body': 'Beautiful day in Portland!'
},
{
'author': {'username': 'Susan'},
'body': 'The Avengers movie was so cool!'
}
]
return render_template('index.html', title='Home', user=user, posts=posts)
Jinja2模板引擎
1.变量
上述代码中用{{ user.username }}结构表示一个变量,这是一种特殊的占位符,告诉模板引擎这个位置的值从渲染模板时使用的数据中获取
Jinja2能识别所有类型的变量,甚至是一些复杂的类型,例如列表,字典和对象
<p> A vlaue from a dictionary: {{ mydict['key'] }}.</p>
<p> A value from a list: {{ mylist[3] }}. </p>
<p> A value from a list, with a variable index: {{ mylist[myintvar]}}. </p>
<p> A value from an object's method: {{ myobj.some_method() }}. </p>
变量的值可以使用过滤器修改,过滤器添加在变量名之后,二者之间以竖线分割
Hello, {{ name|capitalize }}
下列是Jinja2提供的部分常用过滤器
过滤器名 | 说明 |
---|---|
safe | 渲染值时不转义 |
capitalize | 把值的首字母转换成大写,其他字母转换为小写 |
lower | 把值转换成小写形式 |
upper | 把值转换成大写形式 |
title | 把值中每个单词的首字母都转换成大写 |
trim | 把值的首尾空格删掉 |
striptags | 渲染之前把值中所有的HTML标签都删掉 |
safe过滤器特别说明以下,默认情况下,出于安全考虑,Jinja2会转义所有变量,很多情况下需要显示变量中存储的HTML代码,这时就可以用safe过滤器
完整的过滤器列表在Jinja2文档:http://docs.jinkan.org/docs/jinja2/
2.控制结构
Jinja2提供了多种控制结构,可用来改变模板的渲染流程
条件判断语句:
{% if user%}
Hello, {{ user }}!
{% else %}
Hello, Stranger!
{% endif %}
for循环语句:
<ul>
{% for comment in comments %}
<li>{{ comment }}</li>
{% endfor %}
</ul>
Jinja2还支持宏,宏类似于python代码中的函数
{% macro a(comment) %}
<li>{{ comment }}</li>
{% endmacro %}
<ul>
{% for comment in comments %}
<li>{{ a(comment) }}</li>
{% endfor %}
</ul>
为了重复使用宏,可以把宏保存在单独的文件中,然后再需要使用的模板中导入
{% import 'macros.html' as macros %}
<ul>
{% for comment in comments %}
<li>{{ macros.a(comment) }}</li>
{% endfor %}
</ul>
需要再多处重复使用的模块代码片段可以写入单独的文件,再引入所有模板中,以避免重复:
{% include 'common.html' %}
另一种重复使用代码的强大方式是模板继承,类似于python中的类继承
回到我们的工程文件
在我们的 microblog 应用程序中,在页面的顶部需要一个导航栏。在导航栏里面有编辑账号,登出等等的链接。
我们可以在 index.html 模板中添加一个导航栏,但是随着应用的扩展,越来越多的模板需要这个导航栏,我们需要在每一个模板中复制这个导航栏。然而你必须要保证每一个导航栏都要同步,如果你有大量的模板,这需要花费很大的力气。
相反,我们可以利用 Jinja2 的模板继承的特点,这允许我们把所有模板公共的部分移除出页面的布局,接着把它们放在一个基础模板中,所有使用它的模板可以导入该基础模板。
首先创造一个名为base.html的基模板
基模板中定义的区块可在衍生模板中覆盖,Jinja2使用block和endblock指令在基模板中定义内容区块
app/templates/base.html
<html>
<head>
{% if title %}
<title>{{ title }} - Microblog</title>
{% else %}
<title>Welcome to Microblog</title>
{% endif %}
</head>
<body>
<div>Microblog: <a href="/index">Home</a></div>
<hr>
{% block content %}{% endblock %}
</body>
</html>
修改我们的主页
app/templates/index.html
{% extends "base.html" %}
{% block content %}
<h1>Hi, {{ user.username }}!</h1>
{% for post in posts %}
<div><p>{{ post.author.username }} says: <b>{{ post.body }}</b></p></div>
{% endfor %}
{% endblock %}
利用app.run(debug=True)看看效果吧!朋友们!