Flask学习之 Jinja2模板引擎

Flask内置的模板语言,它的设计思想来源于 Django 的模板引擎,并扩展了其语法和一系列强大的功能。

渲染模版函数

Flask提供的 render_template 函数封装了该模板引擎

render_template 函数的第一个参数是模板的文件名,后面的参数都是键值对,表示模板中变量对应的真实值。

1.模板基本使用

1.flask应用对象创建的时候,设置或者保留template_folder参数,创建模板目录

app = Flask(__name__,template_folder='templates')

2.在项目下创建 templates 文件夹,用于存放所有的模板文件,并在目录下创建一个模板html文件 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>{{title}}</h1>
</body>
</html>

3.在视图函数设置渲染模板并设置模板数据

from flask import Flask, render_template
from settings.dev import Config
from flask_script import Manager

"""创建flask应用"""
app = Flask(__name__, template_folder='templates')
"""使用脚手架[终端脚本]启动项目"""
manage = Manager(app)
"""加载配置"""
app.config.from_object(Config)


@app.route("/")
def index():
    return render_template("index.html", title="我的flask网页")


if __name__ == '__main__':
    manage.run()
    # 运行 python manage.py runserver

4.dev.py代码

# 声明一个配置类
class Config(object):
    SECRET_KEY = "DD434O7HQ2131!@#edn#hu!@!g@uWO1NS"

最后目录如下:

http://127.0.0.1:5000/   访问

2.输出变量

{{}} 来表示变量名,这种 {{}} 语法叫做**变量代码块

Jinja2 模版中的变量代码块可以是任意 Python 类型或者对象,只要它能够被 Python __str__ 方法或者str()转换为一个字符串就可以,

比如,可以通过下面的方式显示一个字典或者列表中的某个元素
新增一个接口代码如下:

@app.route("/index02")
def index02():
    data = {}
    data["book_list"] = [
        {"id": 1, "title": "python从入门到精通", "price": 80},
        {"id": 2, "title": "php从入门到精通", "price": 90},
        {"id": 3, "title": "go从入门到精通", "price": 100},
    ]
    data["title"] = "网页标题"
    return render_template("index02.html", **data)

新增一个html文件代码如下:index02.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ title }}</title>
</head>
<body>
<p>输出变量:</p>
<h2>{{ title }}</h2>
{# 模板注释 #}

{# 中括号的方式也可以,但是性能会降低,不推荐使用 #}
<p>输出列表或字典的成员或键值对:</p>
<p>{{ book_list[2]["id"] }}--------{{ book_list[2]["title"] }}------{{ book_list[2]["price"] }}</p>
<p>{{ book_list[1]["id"] }}--------{{ book_list[1]["title"] }}------{{ book_list[1]["price"] }}</p>
<p>{{ book_list.0.id }}--------{{ book_list.0.title }}------{{ book_list.0.price }}</p>

</body>
</html>

3.模板中特有的变量和函数

你可以在自己的模板中访问一些 Flask 默认内置的函数和对象

config

你可以从模板中直接访问Flask当前的config对象:

{{config.DEBUG}}

request

就是flask中代表当前请求的request对象:

{{request.url}}

http://127.0.0.1

session

Flasksession对象

{{session.new}}

True

g变量

在视图函数中设置g变量的 name 属性的值,然后在模板中直接可以取出

{{ g.name }}

url_for()

url_for会根据传入的路由器函数名,返回该路由对应的URL,在模板中始终使用url_for()就可以安全的修改路由绑定的URL,则不比担心模板中渲染出错的链接:

{{url_for('home')}}

如果我们定义的路由URL是带有参数的,则可以把它们作为关键字参数传入url_for(),Flask会把他们填充进最终生成的URL:

{{ url_for('post', post_id=1)}}

/post/1

Index02.html代码改为:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ title }}</title>
</head>
<body>
<p>输出变量:</p>
<h2>{{ title }}</h2>
{# 模板注释 #}

{# 中括号的方式也可以,但是性能会降低,不推荐使用 #}
<p>输出列表或字典的成员或键值对:</p>
<p>{{ book_list[1]["id"] }}--------{{ book_list[1]["title"] }}------{{ book_list[1]["price"] }}</p>
<p>{{ book_list.0.id }}--------{{ book_list.0.title }}------{{ book_list.0.price }}</p>
<p>输出项目的配置信息:</p>
{{ config.DEBUG }}
<P>获取请求对象中的数据:</P>
{{request.url}}
<p>uname = {{ request.args.get("uname") }} </p>
<p>输出session对象:</p>
{{session.new}}
<p>输出g变量:</p>
{{ g.name }}
</body>
</html>

4.流程控制

if/else if /else / endif

for / endfor

Jinja2 语法中的if语句跟 Python 中的 if 语句相似,后面的布尔值或返回布尔值的表达式将决定代码中的哪个流程会被执行.

{%%} 定义的控制代码块,可以实现一些语言层次的功能,比如循环或者if语句

在循环语句的demo中包含了流程控制语句的例子。

5.循环语句

新增一个接口代码:

@app.route("/index03")
def index03():
    data = {}
    data["book_list"] = [
        {"id": 1, "title": "python从入门到精通", "price": 80},
        {"id": 2, "title": "php从入门到精通", "price": 90},
        {"id": 3, "title": "go从入门到精通", "price": 100},
    ]
    data["content"] = "<h1>hello world ha ha</h1>"
    data["content_two"] = "hello world ha ha"
    data["title"] = "网页标题"
    return render_template("index03.html", **data)

新增网页index03.html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <table border="1" width="700">
        <tr>
            <th>ID</th>
            <th>TITLE</th>
            <th>PRICE</th>
        </tr>
        {%  for book in book_list %}
        <tr>
            {%  if book.id%2 %}
            <td style="color: #fff; background: #000;">{{ book.id }}</td>
            {% else %}
            <td style="color: #000; background: #fff;">{{ book.id }}</td>
            {% endif %}

            <td>{{ book.title }}</td>
            <td>{{ book.price }}</td>
        </tr>
        {% endfor %}
    </table>

    {{ content|safe }}
    {{ content_two|truncate(10) }}
    <br>
    {{ content_two|reverse }}
</body>

访问:http://127.0.0.1:5000/index03

效果如下:

6.过滤器

过滤器的本质就是函数。有时候我们不仅仅只是需要输出变量的值,我们还需要修改变量的显示,甚至格式化、运算等等,而在模板中是不能直接调用 Python 中的某些方法,那么这就用到了过滤器。

使用方式:

过滤器的使用方式为:变量名 | 过滤器。

{{variable | filter_name(args1,args2,....)}}

如果没有任何参数传给过滤器,则可以把括号省略掉

{{variable | filter_name }}

如:这个过滤器的作用:把变量variable 的值的首字母转换为大写,其他字母转换为小写

jinja2 中,过滤器是可以支持链式调用的,示例如下:

{{ "hello world" | reverse | upper }}

1常见的内建过滤器

字符串操作

safe:禁用转义

<p>{{ '<em>hello</em>' | safe }}</p>

capitalize:把变量值的首字母转成大写,其余字母转小写

<p>{{ 'hello' | capitalize }}</p>

lower:把值转成小写

<p>{{ 'HELLO' | lower }}</p>

upper:把值转成大写

<p>{{ 'hello' | upper }}</p>

title:把值中的每个单词的首字母都转成大写

<p>{{ 'hello' | title }}</p>

reverse:字符串反转

<p>{{ 'olleh' | reverse }}</p>

format:格式化输出

<p>{{ '%s is %d' | format('name',17) }}</p>

striptags:渲染之前把值中所有的HTML标签都删掉

<p>{{ '<em>hello</em>' | striptags }}</p>

truncate: 符串截断

<p>{{ 'hello every one' | truncate(9)}}</p>

列表操作

first:取第一个元素

<p>{{ [1,2,3,4,5,6] | first }}</p>

last:取最后一个元素

<p>{{ [1,2,3,4,5,6] | last }}</p>

length:获取列表长度

<p>{{ [1,2,3,4,5,6] | length }}</p>

sum:列表求和

<p>{{ [1,2,3,4,5,6] | sum }}</p>

sort:列表排序

<p>{{ [6,2,3,1,5,4] | sort }}</p>

语句块过滤

{% filter upper %}

  #一大堆文字#

{% endfilter %}

2)自定义过滤器

过滤器的本质是函数。当模板内置的过滤器不能满足需求,可以自定义过滤器。自定义过滤器有两种实现方式:

一种是通过Flask应用对象的 add_template_filter 方法

通过装饰器来实现自定义过滤器

重要:自定义的过滤器名称如果和内置的过滤器重名,会覆盖内置的过滤器

案例:给手机进行部分屏蔽

 

main.py代码

from flask import Flask, render_template, request
from config import Config


"""创建flask应用"""
app = Flask(__name__, template_folder='templates')
"""加载配置"""
app.config.from_object(Config)

# 在项目当中,过滤作用的函数,会被放到专门的过滤器文件中
@app.template_filter("mobile")
def do_mobile(data, string):
    return data[:3] + string + data[7:]


@app.route("/")
def index():
    data = {}
    data["user_list"] = [
        {"id": 1, "name": "张三", "mobile": "13112345678"},
        {"id": 2, "name": "张三", "mobile": "13112345678"},
        {"id": 3, "name": "张三", "mobile": "13112345678"},
        {"id": 4, "name": "张三", "mobile": "13112345678"},
    ]
    return render_template("index.html", **data)


if __name__ == '__main__':
    app.run()

模块代码:index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<table border="1" width="700">
    <tr>
        <th>id</th>
        <th>name</th>
        <th>mobile</th>
    </tr>
    {% for user in user_list %}
        <tr>
            <td>{{ user.id }}</td>
            <td>{{ user.name }}</td>
            <td>{{ user.mobile|mobile("****") }}</td>
        </tr>
    {% endfor %}
</table>
<p>
</p>
</body>
</html>

配置文件代码:config.py

# 声明一个配置类
class Config(object):
    SECRET_KEY = "DD434O7HQ2131!@#edn#hu!@!g@uWO1NS"
    DEBUG = True

最后访问结果如下:

7.模板继承

在模板中,可能会遇到以下情况:

多个模板具有完全相同的顶部和底部内容

多个模板中具有相同的模板代码内容,但是内容中部分值不一样

多个模板中具有完全相同的 html 代码块内容

像遇到这种情况,可以使用 JinJa2 模板中的 继承 来进行实现

模板继承是为了重用模板中的公共内容。一般Web开发中,继承主要使用在网站的顶部菜单、底部。这些内容可以定义在父模板中,子模板直接继承,而不需要重复书写。

标签定义的内容

{% block top %} {% endblock %}

  • 相当于在父模板中挖个坑,当子模板继承父模板时,可以进行填充。
  • 子模板使用 extends 指令声明这个模板继承自哪个模板
  • 父模板中定义的块在子模板中被重新定义,在子模板中调用父模板的内容可以使用super()

父模板代码base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    {% block top %}
      <h1>顶部菜单</h1>
    {% endblock top %}

    {% block content %}
    {% endblock content %}

    {% block bottom %}
      <h1>底部</h1>
    {% endblock bottom %}
</body>
</html>

子模板son.html代码:extends指令声明这个模板继承自哪

{% extends 'base.html' %}
{% block content %}
    子模板中间内容
{% endblock content %}

模型的代码:

from flask import Flask, render_template, request
from config import Config


"""创建flask应用"""
app = Flask(__name__, template_folder='templates')
"""加载配置"""
app.config.from_object(Config)

# 在项目当中,过滤作用的函数,会被放到专门的过滤器文件中



@app.route("/")
def index():
    data = {}
    data["user_list"] = [
        {"id": 1, "name": "张三", "mobile": "13112345678"},
    ]
    return render_template("son.html", **data)


if __name__ == '__main__':
    app.run(port=8000, host='0.0.0.0')

配置文件代码config.py

# 声明一个配置类
class Config(object):
    SECRET_KEY = "DD434O7HQ2131!@#edn#hu!@!g@uWO1NS"
    DEBUG = True

上面代码构成下面的目录:

访问:http://127.0.0.1:8000/

得到结果如下图:

模板继承使用时注意点:

  1. 不支持多继承
  2. 为了便于阅读,在子模板中使用extends时,尽量写在模板的第一行。
  3. 不能在一个模板文件中定义多个相同名字的block标签。
  4. 当在页面中使用多个block标签时,建议给结束标签起个名字,当多个block嵌套时,阅读性更好
原文地址:https://www.cnblogs.com/hszstudypy/p/13388637.html