11 KiB
模版简介
模板是一个web
开发必备的模块。因为我们在渲染一个网页的时候,并不是只渲染一个纯文本字符串,而是需要渲染一个有富文本标签的页面。这时候我们就需要使用模板了。在Flask
中,配套的模板是Jinja2
,Jinja2
的作者也是Flask
的作者。这个模板非常的强大,并且执行效率高。以下对Jinja2
做一个简单介绍!
渲染Jinja
模板
要渲染一个模板,通过render_template
方法即可,以下将用一个简单的例子进行讲解:
创建about.html
<h1>welcome back!</h1>
执行下面代码
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/about/')
def about():
return render_template('about.html')
# 渲染 about.html 注意:必须要在 templates 文件夹下
if __name__ == '__main__':
app.run(debug=True,host='0.0.0.0',port=5000)
当访问/about/
的时候,about()
函数会在当前目录下的templates
文件夹下寻找about.html
模板文件。如果想更改模板文件地址,应该在创建app
的时候,给Flask
传递一个关键字参数template_folder
,指定具体的路径,再看以下例子:
from flask import Flask,render_template
app = Flask(__name__,template_folder=r'C:\templates')
@app.route('/about/')
def about():
return render_template('about.html')
以上例子将会在C盘的templates
文件夹中寻找模板文件。还有最后一点是,如果模板文件中有参数需要传递,应该怎么传呢,我们再来看一个例子:
about.html 修改为如下
<h1>welcome {{ user }} </h1>
在渲染模版的时候传递一下参数
@app.route('/about/')
def about():
return render_template('about.html', user='user01')
如果有多个参数要传递的话可以放在字典中
@app.route('/about/')
def about():
return render_template('about.html', **{'user':'alice','name':'bob'})
# about.html 中需要有 user 和 name
以上例子介绍了两种传递参数的方式,因为render_template
需要传递的是一个关键字参数,所以第一种方式是顺其自然的。但是当你的模板中要传递的参数过多的时候,把所有参数放在一个函数中显然不是一个好的选择,因此我们使用字典进行包装,并且加两个*
号,来转换成关键字参数。
Jinja2模版概述
概要
先看一个简单例子:
<html lang="en">
<head>
<title>My Webpage</title>
</head>
<body>
<ul id="navigation">
{% for item in navigation %}
<li><a href="{{ item.href }}">{{ item.caption }}</a></li>
{% endfor %}
</ul>
{{ a_variable }}
{{ user.name }}
{{ user['name'] }}
{# a comment #}
</body>
</html>
以上示例有需要进行解释:
- 第12~14行的
{{ ... }}
:用来装载一个变量,模板渲染的时候,会把这个变量代表的值替换掉。并且可以间接访问一个变量的属性或者一个字典的key
。关于点.
号访问和[]
中括号访问,没有任何区别,都可以访问属性和字典的值。 - 第7~9行的
{% ... %}
:用来装载一个控制语句,以上装载的是for
循环,以后只要是要用到控制语句的,就用{% ... %}
。 - 第16行的
{# ... #}
:用来装载一个注释,模板渲染的时候会忽视这中间的值。
对应的 Python 代码如下
@app.route('/demo1/')
def demo1():
navigation = [
{'href':'http://www.baidu.com','caption':'百度'},
{'href':'http://www.qq.com','caption':'腾讯'}
]
a = 'hello world'
user = {'name':'alice'}
return render_template('demo1.html', navigation=navigation, a_variable=a, user=user)
Jinja2 模版过滤器
过滤器是通过管道符号(|
)进行使用的,例如:{{ name|length }}
,将返回name的长度。过滤器相当于是一个函数,把当前的变量传入到过滤器中,然后过滤器根据自己的功能,再返回相应的值,之后再将结果渲染到页面中。Jinja2
中内置了许多过滤器,在这里可以看到所有的过滤器,现对一些常用的过滤器进行讲解:
-
abs(value)
:返回一个数值的绝对值。 例如:-1|abs
。 -
default(value,default_value,boolean=false)
:如果当前变量没有值,则会使用参数中的值来代替。name|default('alice')
——如果name不存在,则会使用alice
来替代。boolean=False
默认是在只有这个变量为undefined
的时候才会使用default
中的值,如果想使用python
的形式判断是否为false
,则可以传递boolean=true
。也可以使用or
来替换。 -
escape(value)或e
:转义字符,会将<
、>
等符号转义成HTML中的符号。例如:content|escape
或content|e
。 -
first(value)
:返回一个序列的第一个元素。names|first
。 -
format(value,*arags,**kwargs)
:格式化字符串。例如以下代码:
{{ "%s - %s"|format("hello","alice") }}
将输出:Hello - alice
-
last(value)
:返回一个序列的最后一个元素。示例:names|last
。 -
length(value)
:返回一个序列或者字典的长度。示例:names|length
。 -
join(value,d=u'')
:将一个序列用d
这个参数的值拼接成字符串。 -
safe(value)
:如果开启了全局转义,那么safe
过滤器会将变量关掉转义。示例:content_html|safe
。 -
int(value)
:将值转换为int
类型。 -
float(value)
:将值转换为float
类型。 -
lower(value)
:将字符串转换为小写。 -
upper(value)
:将字符串转换为大写。 -
replace(value,old,new)
: 替换将old
替换为new
的字符串。 -
truncate(value,length=255,killwords=False)
:截取length
长度的字符串。 -
striptags(value)
:删除字符串中所有的HTML标签,如果出现多个空格,将替换成一个空格。 -
trim
:截取字符串前面和后面的空白字符。 -
string(value)
:将变量转换成字符串。 -
wordcount(s)
:计算一个长字符串中单词的个数。
控制语句
所有的控制语句都是放在{% ... %}
中,并且有一个语句{% endxxx %}
来进行结束,Jinja
中常用的控制语句有if/for..in..
,现对他们进行讲解:
if
:if语句和python
中的类似,可以使用>,<,<=,>=,==,!=
来进行判断,也可以通过and,or,not,()
来进行逻辑合并操作,以下看例子:
{% if num < 60 %}
你猜的数字小了
{% elif num > 60 %}
你猜的数字大了
{% else %}
你猜对了
{% endif %}
for...in...
:for
循环可以遍历任何一个序列包括列表、字典、元组。并且可以进行反向遍历,以下将用几个例子进行解释:
- 普通的遍历:
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
- 遍历字典:
<dl>
{% for key, value in my_dict.items() %}
<dt>{{ key|e }}</dt>
<dd>{{ value|e }}</dd>
{% endfor %}
</dl>
- 如果序列中没有值的时候,进入
else
:
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% else %}
<li><em>no users found</em></li>
{% endfor %}
</ul>
并且Jinja2
中的for
循环还包含以下变量,可以用来获取当前的遍历状态:
变量 | 描述 |
---|---|
loop.index | 当前迭代的索引(从1开始) |
loop.index0 | 当前迭代的索引(从0开始) |
loop.first | 是否是第一次迭代,返回True或False |
loop.last | 是否是最后一次迭代,返回True或False |
loop.length | 序列的长度 |
另外,不可以使用continue
和break
表达式来控制循环的执行。
测试器
测试器主要用来判断一个值是否满足某种类型,并且这种类型一般通过普通的if
判断是有很大的挑战的。语法是:if...is...
,先来简单的看个例子:
{% if variable is upper %}
value of variable: {{ variable }}
{% else %}
variable is not upper
{% endif %}
以上判断variable
这个变量是否全大写,Jinja
中内置了许多的测试器,看以下列表:
测试器 | 说明 |
---|---|
callable(object) |
是否可调用 |
defined(object) |
是否已经被定义了。 |
escaped(object) |
是否已经被转义了。 |
upper(object) |
是否全是大写。 |
lower(object) |
是否全是小写。 |
string(object) |
是否是一个字符串。 |
sequence(object) |
是否是一个序列。 |
number(object) |
是否是一个数字。 |
odd(object) |
是否是奇数。 |
even(object) |
是否是偶数。 |
赋值(set)语句
有时候我们想在在模板中添加变量,这时候赋值语句(set)就派上用场了,先看以下例子:
{% set name='eagle' %}
那么以后就可以使用name
来代替eagle
这个值了,同时,也可以给他赋值为列表和元组:
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
赋值语句创建的变量在其之后都是有效的,如果不想让一个变量污染全局环境,可以使用with
语句来创建一个内部的作用域,将set
语句放在其中,这样创建的变量只在with
代码块中才有效,看以下示例:
{% with %}
{% set foo = 42 %}
{{ foo }} foo is 42 here
{% endwith %}
也可以在with
的后面直接添加变量,比如以上的写法可以修改成这样:
{% with foo = 42 %}
{{ foo }}
{% endwith %}
这两种方式都是等价的,一旦超出with
代码块,就不能再使用foo
这个变量了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
{% set name="alice" %}
<h1>欢迎{{ name }}</h1>
{% set link=[('http://www.baidu.com','百度'),('http://www.qq.com','腾讯')] %}
<ul>
{% for i in link %}
<li><a href="{{ i[0] }}">{{ i[1] }}</a></li>
{% endfor %}
</ul>
{% set foo=24 %}
{% with foo=88 %}
<p>在局部作用域中的值:{{ foo }}</p>
{% endwith %}
<p>在全局作用域中的值:{{ foo }}</p>
{# with中的修改不会影响全局的内容 #}
</body>
</html>
静态文件的配置
Web
应用中会出现大量的静态文件来使得网页更加生动美观。类似于CSS
样式文件、JavaScript
脚本文件、图片文件、字体文件等静态资源。在Jinja
中加载静态文件非常简单,只需要通过url_for
全局函数就可以实现,看以下代码:
<link href="{{ url_for('static',filename='about.css') }}">
url_for
函数默认会在项目根目录下的static
文件夹中寻找about.css
文件,如果找到了,会生成一个相对于项目根目录下的/static/about.css
路径。当然我们也可以把静态文件不放在static
文件夹中,此时就需要具体指定了,看以下代码:
app = Flask(__name__,static_folder='C:\static')
那么访问静态文件的时候,将会到/static
这个文件夹下寻找。