flask模板的基本用法模板语法渲染模板模板辅助工具

Posted xiaxiaoxu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flask模板的基本用法模板语法渲染模板模板辅助工具相关的知识,希望对你有一定的参考价值。

flask模板

在动态web程序中,视图函数返回的html数据往往需要根据相应的变量(比如查询参数)动态生成。

当HTML代码保存到单独的文件中时,我们没法再使用字符串格式化或拼接字符串的当时在HTML代码中插入变量,这时我们需要使用模板引擎(template engine)。借助模板引擎,我们可以再HTML文件中使用特殊的语法来标记变量,这类包含固定内容和动态部分的可重用文件称为模板(template)。

模板引擎的作用就是读取并执行模板中的特殊语法标记,并根据传入的数据将变量替换为实际值,输出最终的HTML页面,这个过程被称为渲染(rendering)。

Flask默认使用的模板引擎是jinja2,他是一个功能齐全的python模板引擎,输了设置变量,还允许我们在模板中添加if判断,执行for迭代,调整函数等,以各种方式 控制模板的输出。

对于jinja2来说,模板可以是任何格式的纯文本文件,比如HTML、XML、CSV等。

模板的基本用法

下面介绍一下如何使用jinja创建HTML模板,并在视图函数中渲染模板,最终实现HTML响应的动态化

创建模板

假设我们需要编写一个用户的电影清单页面,模板中需要显示用户信息以及用户收藏的电影列表,包含电影的名字和年份。首先创建一些虚拟数据用于测试显示效果:

user = {
    ‘username‘: ‘Grey Li‘,
    ‘bio‘: ‘A boy who loves movies and music.‘
}
movies = [
    {‘name‘ : ‘My Neighbor Totoro‘,‘year‘:‘1988‘},
    {‘name‘: ‘Three Colours trilogy‘, ‘year‘: ‘1993‘},
    {‘name‘: ‘Forrest Gump‘, ‘year‘: ‘1994‘},
    {‘name‘: ‘Perfect Blue‘, ‘year‘: ‘1997‘},
    {‘name‘: ‘The Matrix‘, ‘year‘: ‘1999‘},
    {‘name‘: ‘Memento‘, ‘year‘: ‘2000‘},
    {‘name‘: ‘The Bucket list‘, ‘year‘: ‘2007‘},
    {‘name‘: ‘Black Swan‘, ‘year‘: ‘2010‘},
    {‘name‘: ‘Gone Girl‘, ‘year‘: ‘2014‘},
    {‘name‘: ‘CoCo‘, ‘year‘: ‘2017‘}

 

我们在templates目录下创建一个watchlist.html作为模板文件,然后使用jinja2支持的语法在模板中操作这些变量。

template/watchlist.html:

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ user.username }}‘s Watchlist</title>
</head>
<body>
<a href = "{{ url_for(‘hello‘) }}">&larr; Return</a>
<h2>{{ user.username }}</h2>
{% if user.bio %}
    <i>{{ user.bio }}</i>
{% else %}
    <i>This user has not provided a bio.</i>
{% endif %}
{# 下面是电影清单(这是注释) #}
<h5>{{ user.username }}‘s Watchlist ({{ movies[length] }}):</h5>
<ul>
    {% for movie in movies %}
        <li>{{ movie.name }} - {{ movie.year }}</li>
    {% endfor %}
</ul>
</body>
</html>

在模板中使用的&larr;是HTML实体,HTML实体除了用来转义HTML保留保留符号外,通常会被用来显示不容易通过键盘输入的字符。这里的&larr;会显示为左箭头,另外,&copy;用来显示版权标志。

在模板中添加python语句和表达式时,需要使用特定的定界符把他们标示出来。watchlist.html中设计的模板语法,我们会在下面逐一介绍。首先,可以看到上面的代码中看到Jinja2里常见的三种定界符:

常见的三种定界符

 

1、  语句

比如if判断、for循环等:

{% … %}

2、  表达式

比如字符串、变量、函数调用等:

{{ … }}

3、  注释

{# … #}

另外,在模板中,Jinja2支持使用“.”获取变量的属性,比如user字典中的username键值通过“.”获取,即user.username,在效果上等同于user[‘username’]。

模板语法

利用jinja2这样的模板引擎,我们可以将一部分的程序逻辑放到模板中去。简单地说,我们可以在模板中使用python语句和表达式来操作数据的输出。但需要注意的是,jinja2并不支持所有python语法。并且出于效率和代码组织等方面的考虑,我们应该适度使用模板,仅把和输出控制有关的逻辑操作放到模板中。

jinja2允许你在模板中使用大部分python对象,比如字符串、列表、字典、元组、整型、浮点型、布尔值。它支持基本的运算符号(+、-、*、/等)、比较符号(比如==、!=等)、逻辑符号(and、or、not和括号)以及in、is、None和布尔值(True、False)。

jinja2提供了多种控制结构来控制模板的输出,其中for和if是最常用的两种。jinja2里,语句使用{% … %}表示,尤其需要注意的是,在语句结束的地方,必须添加结束标签:

{% if user.bio %}
    <i>{{ user.bio }}</i>
{% else %}
    <i>This user has not provided a bio.</i>
{% endif %}

在这个if语句里,如果user.bio已经定义,就渲染{%if user.bio%}和{%else%}之间的内容,否则就渲染{%else%}和{%endif%}之间的默认内容。末尾的{%endif%}用来声明if语句的结束,这一行不能省略。

和python里一样,for语句用来迭代一个序列:

<ul>
    {% for movie in movies %}
        <li>{{ movie.name }} - {{ movie.year }}</li>>
    {% endfor %}
</ul>>

和其他语句一样,你需要在for循环的结尾使用endfor标签声明for语句的结束。在for循环内,jinja2提供了多个特殊变量,常用的for循环变量如图:

技术图片

渲染模板

渲染一个模板,就是执行模板的代码,并传入所有在模板中使用的变量,渲染后的结果就是我们要返回给客户端的HTML响应。在视图函数中渲染模板时,我们并不直接使用jinja2提供的函数,而是使用flask提供的渲染函数render_template()

from flask import Flask,render_template
@app.route(‘/watchlist‘)
def watchlist():
    return render_template(‘watchlist.html‘,user=user,movies = movies)

在render_template()函数中,我们首先传入的模板的文件名作为参数。Flask会在程序根目录下的templates文件夹里寻找模板文件,所以这里传入的文件路径是相对于templates根目录的。除了模板文件路径,我们还以关键字参数的形式传入了模板中使用的变量值,以user为里:左边的user表示传入模板的变量名称,右边的user则是要传入的对象。

除了render_template()函数,Flask还提供了一个render_template_string()函数用来渲染模板字符串。

其他类型的变量通过相同的方式传入。传入jinja2中的变量值可以是字符串、列表和字典,也可以是函数、类和类实例,这完全取决于你在视图函数传入的值。

例如:

<p>这时列表my_list的第一个元素:{{ my_list[0] }}</p>

<p>这是元祖my_tuple的第一个元素:{{ my_tutple[0] }}</p>

<p>这是字典my_dict的键为name的值:{{ my_dict[‘name’] }}</p>

<p>这是函数my_func的返回值:{{ my_func() }}</p>

<p>这是对象my_object调用某方法的返回值:{{ my_object.name() }}</p>

 

如果你想传入函数在模板中调用,那么需要传入函数对象本身,而不是函数调用(函数的返回值),所以近些出函数名称即可。当把函数传入模板后,我们可以像在python脚本中一样通过添加括号的方式调用,而且你也可以在括号中传入参数。

根据我们传入的虚拟数据,render_template()渲染后返回的HTML数据如下所示:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Grey Li‘s Watchlist</title>

</head>

<body>

<a href = "/hello">&larr; Return</a>

<h2>Grey Li</h2>

 

    <i>A boy who loves movies and music.</i>

 

 

<h5>Grey Li‘s Watchlist ():</h5>

<ul>

   

        <li>My Neighbor Totoro - 1988</li>

        <li>Three Colours trilogy - 1993</li>

        <li>Forrest Gump - 1994</li>

        <li>Perfect Blue - 1997</li>

        <li>The Matrix - 1999</li>

        <li>Memento - 2000</li>

        <li>The Bucket list - 2007</li>

        <li>Black Swan - 2010</li>

        <li>Gone Girl - 2014</li>

        <li>CoCo - 2017</li>

   

</ul>>

</body>

</html>

在和渲染前的模板文件对比时你会发现,原模板中所有的jinja语句、表达式、注释都会在执行后被移除,而所有的变量都会替换为对应的数据,访问127.0.0.7:5000/watchlist即可以看到渲染后的页面:

 技术图片

模板辅助工具

除了基本语法,jinja2还提供了许多方便的工具,这些工具可以让你更方便的控制模板的输出。为了方便测试,我们在示例程序的templates目录下创建了一个根页面模板index.html。返回主页的index视图和watchlist视图类似:

from flask import render_template

@app.route(‘/‘)
def index():
    return render_template(‘index.html‘)

上下文

模板上下文包含了很多变量,其中包含我们调用render_template()函数时手动传入的变量以及flask默认传入的变量。

除了渲染时传入变量,也可以在模板中定义变量,使用set标签:

{% set navigation = [(‘/’, ‘Home’), (‘/about’, ‘About’)]%}

你也可以将一部分模板数据定义为变量,使用set和endset标签声明开始和结束:

{% set navigation %}
    <li><a href="/">Home</a></li>
    <li><a>href="/about"></a></li>
{% endset %}
内置上下文变量

Flask在模板上下文中提供了一些内置变量,可以在模板中直接使用

技术图片

自定义上下文

如果多个模板都需要使用同一变量,那么比起在多个视图函数中重复传入,更好的办法是能够设置一个模板全局变量。flask提供了一个app.context_processor装饰器,可以用来注册模板上下文处理函数,它可以帮我们完成统一传入变量的工作。模板上下文处理函数需要返回一个包含变量键值对的字典

注册模板上下文处理函数:

@app.context_processor
def inject_foo():
    foo = ‘I am foo.‘
   
return dict(foo=foo)#等同于return {‘foo‘: foo}
当我们调用render_remplate()函数渲染任意一个模板时,所有使用app.context_processor装饰器注册的模板上下文处理函数(包括flask内置的上下文处理函数)都会被执行,这些函数的返回值会被添加到模板中,因此我们可以在模板中直接使用foo变量。
和在render_remplate()函数中传入变量类似,除了字符串、列表等数据结构,你也可以传入函数、类或类实例。
除了使用app.context_processor装饰器,也可以直接将其作为方法调用,传入模板上下文处理函数。
def inject_foo():
    foo = "I am foo."
   
return dict(foo=foo)

app.context_processor(inject_foo)
 
使用lambda可以简化为:
app.context_processor(lambda:dict(foo=‘I am foo.‘))

全局对象

全局对象是指在所有的模板中都可以直接使用的对象,包括在模板中导入的模板

设置全局函数
jinja2在模板中默认提供了一些全局函数,常用的三个函数:

技术图片


除了jinja2内置的全局函数,flask也在模板中内置了两个全局函数

 技术图片

 

flask除了把g、session、config、request对象注册上下文变量,也将他们设置为全局变量,因此可以全局使用。

url_for()用来获取URL,用法和在python脚本相同。在前面给出的watchlist.html模板中,用来返回主页的链接直接写出。在实际的代码中,这个URL使用url_for()生成,传入index视图的端点(index):

<a href=”{{ url_for(‘index’) }}”>&larr; Return</a>

 

自定义全局函数

除了使用app.context_processor注册模板上下文处理函数来传入变量,我们也可以使用app.template_global装饰器直接将函数注册为模板全局函数。比如,下面例子把bar()函数注册为模板全局函数。

@app.template_global()
def bar():
    return ‘I am bar.‘

默认使用函数的原名称传入模板,在app.template_global()装饰器中使用name参数可以指定一个自定义名称。app.template_global()仅能用于注册全局函数。

 

你可以直接使用app.add_template_global()方法注册自定义全局函数,传入函数对象和可选的自定义名称(name),比如app.add_template_global(your_global_function)。

以上是关于flask模板的基本用法模板语法渲染模板模板辅助工具的主要内容,如果未能解决你的问题,请参考以下文章

Flask整合html模板

flask基础之jinja2模板-语法定义

Flask 的 template模板 与 jinja2语法

golang 模板(template)的常用基本语法

Flask: 渲染模板

Flask模板