Jinja2的介绍


  • Flask 是使用 Jinja2 这个模板引擎来渲染模板

  • Jinja2 的模板语言更加贴近于 Python 的语法

  • Jinja2 的模板语言大部分都支持Python的语法,Django 的不行

  • Jinja2 和 Django 模板语言的区别:
    • Jinja2 的模板语言支持大部分的Python语法
    • Jinja2 在调用对象方法 或者 函数的时候必须加括号()
    • Jinja2 可以调用带参数的对象方法 或 函数

  • 注意: 因为 Jinja2 和 Django 模板语言的用法和语法差不多(即: Django 有的 Jinja 也都有),这里就不详细列举了,只是列举一些不一样的知识点

变量


  • Jinja2 的模板语言大部分都支持Python的语法,所以在模板中可以使用Python的语法

  • Jinja2 在调用对象方法 或者 函数的时候必须加括号()

  • Jinja2 可以调用带参数的对象方法 或 函数


# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.route('/index')
def index():
    lis = [1, 2, 3, 4]

    dic = {
        'name': 'Kevin',
        'age': 18
    }

    lis_dic = [
        {'width': 120, 'height': 75},
        {'background': 'red', 'color': '#fff'}
    ]

    def no_data_fn():
        return '没有参数的函数'

    def data_fn(n1, n2):
        return n1 + n2

    class Person():
        def __init__(self, username, address):
            self.username = username
            self.address = address

        def dream(self):
            return '{}在做梦'.format(self.username)

        def p_fn(self, data):
            return '{}-{}'.format(self.username, data)

    kevin = Person('Kevin', '横沥')
    aimer = Person('Aimer', '日本')
    eric = Person('Eric', '东莞')

    obj_lis = [kevin, aimer, eric]

    res_dic = {
        'lis': lis,
        'dic': dic,
        'lis_dic': lis_dic,
        'no_data_fn': no_data_fn,
        'data_fn': data_fn,
        'user_obj': kevin,
        'obj_lis': obj_lis
    }

    return render_template('index.html', **res_dic)


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

# index.html

<p>
{# 获取列表的第二个参数 -> 2 #}
    {{ lis.1 }}
 {# python语法的写法 #}
    {{ lis[1] }}
</p>
<p>
 {# 获取字典中指定的key值 -> Kevin #}
    {{ dic.name }}
{# python语法的写法 #}
    {{ dic["name"] }}
    {{ dic.get("name") }}
</p>
<p>
{# 获取列表中第二个参数字典中指定的key值 -> #fff #}
    {{ lis_dic.1.color }}
{# python语法的写法 #}
    {{ lis_dic[1]["color"] }}
    {{ lis_dic[1].get("color") }}
</p>
<p>
{# 调用函数 #}
    {{ no_data_fn() }}
    {{ data_fn(1, 2) }}
</p>
<p>
{# 调用对象中的属性 -> Kevin #}
    {{ user_obj.username }}
</p>
<p>
{# 调用对象中的方法 #}
    {{ user_obj.dream() }}
    {{ user_obj.p_fn("html_data") }}
</p>
<p>
{# 获取对象列表中的指定序列对象的属性 #}
    {{ obj_lis.1.username }}
{# python语法的写法 #}
    {{ obj_lis[1].username }}
</p>
<p>
{# 调用对象列表中的指定序列对象的不带参数的方法 #}
    {{ obj_lis.1.dream() }}
    {{ obj_lis.1.p_fn("html_data") }}
{# python语法的写法 #}
    {{ obj_lis[1].dream() }}
    {{ obj_lis[1].p_fn("html_data") }}
</p>

全局模板函数


全局模板函数作用于所有模板(即: 在任何模板中都可以调用该方法)

两种作用: 

  • template_global() 装饰器 和 Django 模板语言中的 inclusion_tag 类似

  • 当有两个或以上的视图函数都需要传递同一个函数给自身模板的时候可以使用全局模板函数

1. 装饰器写法

# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.template_global()
def t_fn(n1, n2, n3):
    return n1 + n2 + n3


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


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

# index.html

{{'{'+'{'+' t_fn(1, 2, 3) '+'}'+'}'}}

2. 调用Flask对象方法的写法

  • 语法: app.add_template_global(函数, name='别名')

# app.py

from flask import Flask, render_template

app = Flask(__name__)


def t_fn(n1, n2, n3):
    return n1 + n2 + n3


app.add_template_global(t_fn, name='t_fn')


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


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

# index.html

{{'{'+'{'+' t_fn(1, 2, 3) '+'}'+'}'}}

自定义过滤器


1.装饰器写法

# app.py

from flask import Flask, render_template

app = Flask(__name__)


@app.template_filter()
def t_filter(n1, n2, n3):
    print(n1, n2, n3)  # 2 3 4
    return n1 + n2 + n3


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


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

# index.html

{{'{'+'{'+' 2|t_filter(3, 4) '+'}'+'}'}}

2. 调用Flask对象方法的写法

  • 语法: app.add_template_filter(函数, name='过滤器别名')

# app.py

from flask import Flask, render_template

app = Flask(__name__)


def t_filter(n1, n2, n3):
    print(n1, n2, n3)  # 2 3 4
    return n1 + n2 + n3


app.add_template_filter(t_filter, name='t_filter')


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


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

# index.html

{{'{'+'{'+' 2|t_filter(3, 4) '+'}'+'}'}}

母板


  • 将多个页面都相同的部分抽出取来定义成母板,然后子页面通过代码替换模板中预先定义好带名字的块

  • 我们通常会在母板中定义页面专用的CSS块和JS块,方便子页面使用自身独有的css和js

# 在母版中定义块的固定写法

{% block 块的名字 %}

{% endblock %}

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Title</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link rel="stylesheet" href="">
{# 定义被子页面所替换的js块,方便子页面使用自身独有的css #}
    {% block page_css %}

    {% endblock %}
</head>
<body>

<h1>这是母版的标题</h1>

{# 定义被子页面所替换的块 #}
{% block page_main %}

{% endblock %}

{# 定义被子页面所替换的js块,方便子页面使用自身独有的js #}
{% block page_js %}

{% endblock %}
<script type="text/javascript"></script>
</body>
</html>

继承母板


  • 在子页面中最上方使用下面的语法来继承母板

{% extends '母版路径' %} -> 母版路径默认就是在templates下,所以templates可以省略不写

{% extends 'master/m_index.html' %}

块(block)


  • 在子页面中替换母版定义好的块

# 固定写法

{% block 母版中所定义块的名字 %}
html内容
{% endblock %}

# 子页面.html

{# 继承母版 #}
{% extends 'master/m_index.html' %}

{# 替换母版中所定义好的块 #}
{% block page_main %}
    <div>这是HTML的内容</div>
    <ul>
        <li>内容一</li>
        <li>内容二</li>
        <li>内容三</li>
    </ul>
{% endblock %}

组件


  • 可以将常用的页面内容如导航条,页尾信息等组件保存在单独的html文件中,然后在需要的页面中按如下语法导入即可

{% include '组件路径' %} -> 组件路径默认就是在templates下,所以templates可以省略不写

# xxx.html

{% include 'component/nav.html' %}


  • 宏 类似于 Python 中的函数(即: 在模板中编写和使用函数)

  • 宏 里面的html标签默认是不会被渲染的,只有调用了 宏 才会进行渲染与函数的特性一样

1. 语法

{# 定义宏 #}
{% macro 宏名字(参数参数, ……) %}
html标签
{% endmacro %}

{# 调用宏 #}
{{'{'+'{'+' 宏名字(数据数据, ……) '+'}'+'}'}}

2. 混合写法

# index.html

{# 定义宏 #}
{% macro input_macro(name, type='text', value='') %}
    <h1>宏</h1>
    <input name="{{ name }}" type="{{ type }}" value="{{ value }}">
    <input type="submit" value="提交">
{% endmacro %}

{# 调用宏 #}
{{'{'+'{'+' input_macro(name='username') '+'}'+'}'}}
{{'{'+'{'+' input_macro(name='password', type='password') '+'}'+'}'}}


3. 拆分写法

# macro.html

{# 定义宏 #}
{% macro input_macro(name, type='text', value='') %}
    <h1>宏</h1>
    <input name="{{ name }}" type="{{ type }}" value="{{ value }}">
    <input type="submit" value="提交">
{% endmacro %}

# index.html

{# 导入 macro.html #}
{% import 'macro.html' as m_h %} {# m_h 就是 macro.html 的别名 #}

{# 调用宏 #}
{{'{'+'{'+' m_h.input_macro(name='username') '+'}'+'}'}}
{{'{'+'{'+' m_h.input_macro(name='password', type='password') '+'}'+'}'}}