Flask模板引擎:Jinja2常用语法整理

摘要:FlaskJinja2HTML

Flask模板引擎Jinja2简述

模板实质上是一个静态的包含HTML语法的全部或片段的文本文件,也可以包含变量表示的动态部分使用真实值替换网页模板中的变量,生成对应数据的HTML片段,这一过程称为渲染,Falsk使用Jinja2模板引擎来渲染模板,简单而言Jinja2就是一种基于Python的在HTML代码中对动部分进行一系列操作的语法
Flask中使用render_template来渲染模板,render_template的首个入参是模板文件的名称,Falsk会从项目根目录下的templates目录下查找模版。先创建一个first.html




    
    这是一个测试


    

这是一个测试

在视图函数中使用render_template渲染模板

from flask import render_template

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

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

向模板中传递参数

Flask可以将程序中的参数或变量传入指定的模板进行渲染,在HTML文件中使用{{ }}将程序中指定的参数进行传入。修改first.html




    
    这是一个测试


    

这是一个测试 {{ name }}

在渲染方法render_template中传入参数,指定模板中动态变量的名字等于程序中的参数名,必须指定模板中的动态变量名

@app.route('/template_test')
def template_test():
    my_name = "你好"
    return render_template('first.html', name=my_name)

传入多个变量可以直接使用**locals()方法,此时模板中动态变量的名称要和程序中的参数名称一致,如下修改视图函数

@app.route('/template_test')
def template_test():
    name = "你好"
    return render_template('first.html', **locals())

Jinja2控制语句

Jinja2中的控制语句用来控制渲染的方向,使用iffor关键字,放在{%%}使用

if控制语句

if控制语句的基础语法

{% if condition %}
    

do something

{% else %}

do something

{% endif %}

编写一个HTML其中通过判断变量name在程序中是否存在来呈现不同的展示结果




    
    这是一个测试


    {% if name %}
        

存在name

{% else %}

不存在name

{% endif %}

在视图函数中将name注释掉,此时不存在name程序变量,返回页面结果为"不存在name"。

@app.route('/template_test')
def template_test():
    # name = "你好"
    return render_template('first.html', **locals())

多个分支条件判断




    
    这是一个测试


    {% if age == 1 %}
        

age为1

{% elif age == 2 %}

age为2

{% else %}

age不为1和2

{% endif %}

组合判断逻辑,支持python and or




    
    这是一个测试


    {% if age >= 1 and age < 3 %}
        

age为[1, 3)

{% elif age >= 3 and age < 4 %}

age为[3, 4)

{% else %}

age为其他

{% endif %}

可以在html标签中使用jinja2控制语句,实现不同条件不同样式的按钮

{% for cate in category_list %}
    
{% endfor %}
按钮标签不同样式.png
for控制语句

for控制语句的基础语法

{% for 目标 in 对象 %}
    

do something

{% endfor %}

Jinja2的for循环变量不需要{{ }}传入,不支持continue和break,但是和Python一样可以对Python的可迭代对象进行循环遍历。在一个循环代码块内部调用loop的属性可以获得循环中的状态数据,比如可以一边循环一边拿到下标,包括

loop.index: 当前迭代的索引(从1开始)
loop.index0: 当前迭代的索引(从0开始)
loop.first: 是否是第一次迭代,返回True,False
loop.last: 是否是最后一次迭代,返回True,False
loop.length: 返回序列长度

在HTML中构建一个for循环语句,每一次循环的对象是一个字段,使用.key直接拿到value值




    
    这是一个测试


    {% for good in goods %}
        

{{ good.name }}

{{ good.price }}

{% endfor %}

在视图函数中创建一个字典对象传入模板

@app.route('/template_test')
def template_test():
    goods = [{"name": "苹果", "price": 32}, {"name": "橘子", "price": 99}]
    return render_template('first.html', **locals())

也可以使用Python字段的语法拿到值

    {% for good in goods %}
        

{{ good["name"] }}

{{ good["price"] }}

{% endfor %}

在代码块中使用loop关键字




    
    这是一个测试


    {% for good in goods %}
        

{{ good.name }}

{{ good.price }}

循环长度{{ loop.length }}

当前索引{{ loop.index0 }}

是否结束{{ loop.last }}

{% endfor %}
Flask模板引擎:Jinja2常用语法整理_第1张图片
查看循环展示结果.png

Python中的range可以结合for循环一起使用,在jinja2中也可以直接使用

    {% for i in range(20) %}
        

{{ i }}

{% endfor %}

Jinja2的过滤器

过滤器的本质是一个转换函数,有时候不仅需要输出程序参数还要对参数进行修改转换才能输出,此时需要用到过滤器,过滤器写在变量后面,中间用|隔开,|左右没有空格

字符串过滤器
  • default: 如果程序中没有该参数则可以输出一个默认值,如果程序中存在该参数,但是是None""0False,可以设置第二个参数,如果设为true则以上0值输出也跳转到默认值,false则保留原始空值输出,默认不写的话就是false

{{ name|default('小明', true)}}

这个过滤器也可以用or关键字实现,和Python语法一致,如果前项为空输出后项,无此参数和有参数但是为空都会走or逻辑

{{ name or '小明'}}


  • replace: 替换,和Python语法一致,多个过滤器可以连续写

{{ name|default('小明')|replace('小', '大')}}

  • trim: 去除收尾空格

{{ ' 去除收尾空格 '|trim }}

  • ~:字符串连接,传入name='小明',输出"我和小明出去玩了"

{{ '我和'~name~'出去玩了'}}


可迭代对象过滤器
  • firstlast:获得列表的第一个和最后一个元素
    

第一个元素{{ items|first }}

最后一个元素{{ items|last }}

在视图函数中传递一个列表

@app.route('/template_test')
def template_test():
    items = [1, 3, 5, 7, 9]
    return render_template('first.html', **locals())

输出为"第一个元素1 最后一个元素9"

  • count: 返回列表的长度

列表长度{{ items|count }}

  • maxmin求一个列表的最大最小值

{{ ent_scores|max }}

{{ ent_scores|min }}

  • join:列表转字符串,和Python语法一致,可以指定分隔符,输出为"列表转字符串1,3,5,7,9"

列表转字符串{{ items|join(',') }}

  • sort:排序,默认不传参是正序排序,传入reverse=true是降序

列表升序{{ items|sort }}

列表降序{{ items|sort(true) }}

可以指定属性排序,比如需要排序的对象是一个字典集合

items = [{"name": "苹果", "price": 23}, {"name": "西瓜", "price": 33}, {"name": "西红柿", "price": 25}]

为sort过滤器增加attribute字段指定排序属性,效果如下

    

根据某个属性排序{{ items|sort(attribute='price', reverse=true) }}

{% for item in items|sort(attribute='price', reverse=true) %}

{{ item.name }}

{% endfor %}
Flask模板引擎:Jinja2常用语法整理_第2张图片
指定属性排序.png
  • reverse: 可迭代对象反转,字符串和集合都可以

{{ '12345'|reverse }}

{{ [1, 2, 3, 4, 5]|reverse|join(',')}}

数值对象过滤器
  • round: 保留小数,比如保留2为小数

{{ 2.222|round(2) }}

  • string:转化为字符串,如果程序传入的参数是数值,在模板中需要进行字符串操作需要转string

{{ 2.22|string + '你好'}}

  • int:转化为整数,向下取整

{{ 2.222|int }}

  • abs: 转化为绝对值

{{ -2.222|abs }}

  • -:直接取负号,取相反数,如下num输入为3,最终输出为0

{{ -num + 3}}

其他jinja2的内置过滤器参考http://www.pythontip.com/blog/post/5455/


过滤器的执行顺序

如果一个{{ }}表达式中既存在过滤器,又存在Python的基本语句,如运算,其他关键字等,过滤器总是和他之前紧贴的那个元素相连,即过滤器优先级最高,因此必要的时候需要使用( )来控制过滤器的范围,比如

{{ (ent_rank * 100)|int ~"%"}}

如果不加入括号,则对ent_rank int取整无效,因为他只对100有效

自定义过滤器

可以自己用Python语言实现一个自定义过滤器使用add_template_filter进行注册调用,或者使用修饰器template_filter注册

@app.template_filter('t_func')
def t_func(t):
    t2 = time.time()
    diff = t2 - t
    if diff < 60:
        return "刚刚"
    elif 60 <= diff < 60 * 60:
        return "%d分钟之前" % int(diff / 60)
    elif 3600 <= diff < 3600 * 24:
        return "%d小时之前" % int(diff / 3600)
    else:
        return "很久之前"

另一种注册方式

def t_func(t):
    t2 = time.time()
    diff = t2 - t
    if diff < 60:
        return "刚刚"
    elif 60 <= diff < 60 * 60:
        return "%d分钟之前" % int(diff / 60)
    elif 3600 <= diff < 3600 * 24:
        return "%d小时之前" % int(diff / 3600)
    else:
        return "很久之前"

app.add_template_filter(t_func, 't_func')

HTML模板




    
    这是一个测试


    

文章发表于{{ t| t_func }}

最终显示结果为"文章发表于很久之前"
自定义过滤器可以带有一个或者多个参数,函数的第一个参数作为需要渲染转化的参数,后面的参数可以在过滤器括号中指定作为辅助参数,比如

def score_grade(score: int, add: str):
    if score >= 90:
        return "高风险" + add
    elif 90 > score >= 80:
        return "中度风险" + add
    elif 80 > score >= 60:
        return "低风险" + add
    elif 60 > score:
        return "良好" + add

detail.add_app_template_filter(score_grade, 'score_grade')

以上函数除了要转化的score,还增加一个可变参数,在模板中的使用,过滤器后面使用( )传递参数,如果要传递的参数也是需要渲染的变量,不需要再加{{ }},在外{{ }}内整体渲染

风险等级: 风险等级为{{ ent_score|score_grade('aaa') }}

Flask模板引擎:Jinja2常用语法整理_第3张图片
带有参数的过滤器.png

Jinja2编写宏和导入应用宏

宏类似函数,将一个逻辑块中变动的部分单独抽出来作为参数,其他固定的部分包装在一个程序块中,jinja2中定义宏的关键字是macro。如下在html中定义一个宏input,有name,type,value三个参数,后面两个参数有默认值,这三个参数对应h5的input的标签,实际上就是用一个宏实现了多种样式的input标签。




    
    这是一个测试


{% macro input(name, type='text', value='') %}
    
{% endmacro %}

用户名:{{ input('username') }}

密码:{{ input('password', type='password') }}

用户名:{{ input('submit', type='submit', value='提交') }}

定义好宏之后,使用{{ 宏(参数) }}进行调用,效果如下

Flask模板引擎:Jinja2常用语法整理_第4张图片
宏的定义和调用.png


一个宏可以被多个h5模板导入使用,所以需要将所有的宏写在一个h5中,导入的方法类似Python的import。首先新建一个h5命名为macro.html

{% macro input(name, type='text', value='') %}
    
{% endmacro %}

在另一个模板中导入




    
    这是一个测试


{% import 'macro.html' as macro %}

用户名:{{ macro.input('username') }}

密码:{{ macro.input('password', type='password') }}

用户名:{{ macro.input('submit', type='submit', value='提交') }}

也可以直接从模板中导入宏,使用from import导入




    
    这是一个测试


{% from 'macro.html' import input %}

用户名:{{ input('username') }}

密码:{{ input('password', type='password') }}

用户名:{{ input('submit', type='submit', value='提交') }}


include的使用

jinja2中将一个模板引入到另一个模板的指定位置使用关键字include,比如引入公共部分,header.html,footer.html等,先创建公共头部和尾部的h5,include导入的模板必须在templates目录下




    
    header


这是网页头部



    
    footer






另外编写一个模块,使用include导入header.html和footer.html,在主模板中定义的css样式可以被include导入的模板使用




    
    这是一个测试
    


{% include "header.html" %}
这是正文
{% include "footer.html" %}

效果如下


Flask模板引擎:Jinja2常用语法整理_第5张图片
include导入模板.png

使用set和with赋值变量

jinja2中setwith都可以对变量进行定义和赋值,set定义的在整个模板范围中都有效,with定义的变量有作用范围,with的作用就是定义这个范围,分别用set和with定义变量如下




    
    这是一个测试


{% set a='123' %}

set的值{{ a }}

{% with b='321' %}

with的值{{ b }}

{% endwith %}

调用定义的值使用{% %},如果在with外面调用在with内部定义的值则无效
如果在一个with语句中存在需要需要渲染的变量则直接写入变量名,不需要再加渲染花括号,如果with语句中有多个变量需要定义,中间用逗号隔开,如下

{% with ent_score_diff = ent_scores[-1] - ent_scores[0], ent_max_min_diff = ent_scores|max - ent_scores|min %}

静态文件的加载 url_for

需要先创建static文件夹,再创建子文件夹cssjsimages,同时需要使用url_for函数。

(1)导入js

也可以使用更通用额方式


(2)导入图片
 
(3)导入css


模板的集成extends

一个系统的网站每个网页需要有统一的结构,比如每个网页都有标题,内容,底部等几个部分,模板继承的目的就是将相同的部分提取出来,形成一个base.html。在jinja2中使用extends关键字。
模板的继承包含基本模板子模板,子模板继承基本模板,基本模板包含了基本骨架,其中有一些空的不完善的块block需要子模板来填充,不同的block之间用不同的名字区分,因此每个block还需要定义一个名字,比如父模板如下




    
    {% block title %}{% endblock %}


{% block body%}
    

这是基础身体

{% endblock %} {% block footer %}

这是尾巴

{% endblock %}

在新模板中继承,继承骨架重写title,body,footer三个block,其中{{ super() }}方法是使得基础框架中原有的block内的内容保留,默认子模板中的block代码会把基础模块中的对应的block代码覆盖。

{% extends "base.html" %}
{% block title%}这是继承的title{% endblock %}
{% block body %}
    {{ super() }}
    

继承的身体

{% endblock %} {% block footer %}

继承的尾巴

{% endblock %}

效果如下


Flask模板引擎:Jinja2常用语法整理_第6张图片
模板继承.png

Jinja2的空白控制

在最终输出的网页HTML中,Jinja2中的表达式会保留移除后的空行,比如如果模板代码如下

{% if True %} yay {% endif %}

最终在浏览器看到的网页源代码是

yay

这是由于Jinja2表达式留下的空行和jinja2的缩进导致的,但是多余的空白不影响浏览器的解析,却影响HTML文件体积大小,降低数据传输速度,因此在代码部署前需要去除空格空行,对于缩进没有强制要求,但是为了代码的可读性,建议在HTML代码中的Jinja2语句中加入缩进。
去除空格空行可以在Jinja2语句的分隔符的%旁边加入减号-,紧贴,没有空格,比如

{% for industry_ent in industry_ents[:5] %}

{{ industry_ent }}

{% endfor %}

渲染之后的HTML代码为


Flask模板引擎:Jinja2常用语法整理_第7张图片
带有空白的html.png

在分隔符中加入-号

{% for industry_ent in industry_ents[:5] -%}

{{ industry_ent }}

{%- endfor %}

起始语句-加载右边,带有语句右边的空白去除,结束语句-加载左边,说明语句左边的空白去除,此时再看浏览器的源码如下:


去除空白的html.png

另一种方法是在app中配置jinja的环境参数,就不要在在Jinja2语法的时候时刻注意要写-号了

app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True

但是宏内的空白不收这两个环境参数控制,还是需要在宏分隔符中手动加入-号,例如

{% macro score_grade_img(filename, width="250", height="220") %}
    
{% endmacro %}

手动加入-号

{% macro score_grade_img(filename, width="250", height="220") -%}
    
{%- endmacro %}

你可能感兴趣的:(Flask模板引擎:Jinja2常用语法整理)