flask(七):模板的基本用法

目录

模板的基本用法

创建模板

常见的3种定界符

模板语法

渲染模板

从本篇我们开始介绍模板在flask中的使用,先看一个简单的例子:

# encoding=utf-8
from flask import Flask, request, url_for, redirect
from urllib.parse import urlparse, urljoin
app = Flask(__name__)


post_body = "Flask is a lightweight WSGI web application framework. " \
            "It is designed to make getting started quick and easy, " \
            "with the ability to scale up to complex applications. " \
            "It began as a simple wrapper around Werkzeug and Jinja " \
            "and has become one of the most popular Python web application frameworks.." \
            " Flask offers suggestions, but doesn't enforce any dependencies or project layout."


@app.route('/hi')
def hi():
    return """
    <h1>A very long post</h1>
    <div class="body">%s</div>
    <scrip src= src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script type="text/javascript"></script>
    """ % post_body


if __name__ == "__main__":
    app.run(debug=True)

执行结果:

 

在动态web程序中,视图函数返回的HTML数据往往需要根据相应的变量(比如查询参数)动态生成。当HTML代码保存到单独的文件中时,我们没法再使用字符串格式化或者拼接字符串的方式在HTML代码中插入变量,这是我们需要使用模板引擎(template engine)。借助模板引擎,我们可以在HTML文件中使用特殊的语法来标记变量,这类包含固定内容和动态部分的可重用文件称为模板(template)。

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

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

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

 

模板的基本用法

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

创建模板

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

代码示例:

app.py

# encoding=utf-8
from flask import Flask, render_template
app = Flask(__name__)


user = {"username": "xiaoxiao",
         "bio": "A girl who loves movies."}

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'}
]


@app.route('/hi')
def hi():
    return "hello flask!"


@app.route("/watchlist")
def watchlist():
    return render_template("watchlist.html", user=user, movies=movies)


if __name__ == "__main__":
    app.run(debug=True)

在template目录中新建名为watchlist.html文件,然后使用jinja2支持的语法在模板中操作这些变量,内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ user.username }}'s watchlist</title>
</head>
<body>
<a href="{{ url_for('hi') }}">← 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>

浏览器访问:http://127.0.0.1:5000/watchlist

 

HTML文件说明:

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

在模板中添加python语句和表达式时,需要使用特定的定界符将其标识。watchlist.html中提到的语法我们会在下面逐一介绍

常见的3种定界符

jinja2中常见的3种定界符如下:

语句:{{%...%}}  适用于if判断,for循环等

表达式:{{ ... }}  适用于字符串、变量、函数调用等

注释:{{ #...#}}

另外,在模板中,jinja2支持使用”.”获取变量的属性,比如user字典中的username键值通过”.”获取即可。比如,user.username等价于user[username]

模板语法

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

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

jinja2通过了多种控制结构来控制模板的输出,其中for和if是最常用的2种。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循环变量如下:

变量名

作用

loop.index

当前迭代数,从1开始计数

loop.index()

当前迭代数,从0开始计数

loop.revindex

当前反向迭代数,从1开始计数

loop.revindex()

当前反向迭代数,从0开始计数

loop.first

如果是第一个元素则为True

loop.last

如果是最后一个元素则为True

loop.previtem

上一个迭代的条目

loop.nextitem

下一个迭代的条目

loop.length

序列中元素的数量

loop的例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ user.username }}'s watchlist</title>
</head>
<body>
<a href="{{ url_for('hi') }}">← 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>loop.index:{{ loop.index }}  loop.first:{{ loop.first }}
         loop.last:{{ loop.last }} - {{ movie.name }} - {{ movie.year }}</li>
    {% endfor %}
</ul>
</body>
</html>

浏览器访问:http://127.0.0.1:5000/watchlist

 

​​​​​​​渲染模板

渲染模板就是执行模板中的代码,并传入所有在模板中使用的变量,渲染后的结果就是要返回给客户端的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模板的语法进行字符的处理,不能通过文件的方式。

# encoding=utf-8
from flask import Flask, render_template_string
app = Flask(__name__)


user = {"username": "xiaoxiao",
         "bio": "A girl who loves movies."}

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'}
]


@app.route('/hi')
def hi():
    return "hello flask!"


@app.route("/watchlist")
def watchlist():
    return render_template_string(
        """{% for movie in movies %}
            <li>{{ movie.name }} - {{ movie.year }}</li>
            {% endfor %}
        """, movies=movies)


if __name__ == "__main__":
    app.run(debug=True)

浏览器访问:http://127.0.0.1:5000/watchlist

​​​​​​​

 

其它类型的变量通过相同的方式传入。传入jinja2中的变量值可以是字符串、字典、列表,元组,也可以是函数和类实例

模板中新建testJinja.html文件,内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>testJinja</title>
</head>
<body>
<p>这是列表my_list的第一个元素:{{ my_list[0] }}</p>
<p>这是元组my_tuple的第一个元素:{{ my_tuple[0] }}</p>
<p>这是字典my_dict的键为name的值:{{ my_dict['name'] }}</p>
<p>这也是字典my_dict的键为name的值:{{ my_dict.name }}</p>
<p>这是函数my_func的返回值:{{ my_func() }}</p>
<p>这是对象my_str调用upper方法的返回值:{{ my_str.upper() }}</p>

</body>
</html>

app.py内容如下:

# encoding=utf-8
from flask import Flask, render_template_string, render_template
app = Flask(__name__)

my_list = [1, 2, 3, 4]
my_tuple = ('a', 'b', 'c')
my_dict = {"name": "xiaoxiao", "age": 18}
my_str = "my string"


def my_func():
    return "This is my_func"


@app.route("/testJinja")
def testJinja():
    return render_template("testJinja.html", my_list=my_list,
                           my_tuple=my_tuple, my_dict=my_dict,
                           my_str=my_str, my_func=my_func)


if __name__ == "__main__":
    app.run(debug=True)

浏览器访问:http://127.0.0.1:5000/testJinja

 

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

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

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>xiaoxiao's watchlist</title>

</head>

<body>

<a href="/hi">← Return</a>

<h2>xiaoxiao</h2>



    <i>A girl who loves movies.</i>





<h5>xiaoxiao's watchlist (10):</h5>

<ul>

    

        <li>loop.index:1  loop.first:True

         loop.last:False - My Neighbor Totoro - 1988</li>

    

        <li>loop.index:2  loop.first:False

         loop.last:False - Three Colours trilogy - 1993</li>

    

        <li>loop.index:3  loop.first:False

         loop.last:False - Forrest Gump - 1994</li>

    

        <li>loop.index:4  loop.first:False

         loop.last:False - Perfect Blue - 1997</li>

    

        <li>loop.index:5  loop.first:False

         loop.last:False - The Matrix - 1999</li>

    

        <li>loop.index:6  loop.first:False

         loop.last:False - Memento - 2000</li>

    

        <li>loop.index:7  loop.first:False

         loop.last:False - The Bucket list - 2007</li>

    

        <li>loop.index:8  loop.first:False

         loop.last:False - Black Swan - 2010</li>

    

        <li>loop.index:9  loop.first:False

         loop.last:False - Gone Girl - 2014</li>

    

        <li>loop.index:10  loop.first:False

         loop.last:True - CoCo - 2017</li>

    

</ul>

</body>

</html>

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

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值