Flask的Jinjia2模板

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/guanchunsheng/article/details/79093803

简单说:
- 业务逻辑
python代码部分
- 表现逻辑
HTML代码部分

这两个部分最好解耦,不然很难维护。

渲染
使用模板,用运行时真实的值替换模板中的可变部分,生成最终的响应字符串,这样的过程叫渲染。

Flask使用Jinjia2模板引擎

1. 模板文件

模板文件保存在 templates子文件夹中,Flask会在这里寻找模板。
举个例子,编写以下2个html模板文件并放在templates目录内:

<!-- index.html文件 -->
<h1>Hello World!</h1>

<!-- user.html文件 -->
<h1>Hello, {{ name }}!</h1>

然后在python代码中使用模板渲染:

# hello.py文件
from flask import Flask, render_template

app = Flask(__name__)

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

@app.route('/user/<name>')
def user(name):
    return render_template('user.html', name = name)

if __name__ == '__main__':
    app.run(host="10.xxx.xxx.184", port=80, debug=True)

模板渲染函数render_template的参数,第一个参数是模板html文件,后面的参数是真实键值对,用于替换模板中的变量。注意键值对的名字空间,本例中左边的name是模板文件名字空间中的变量名,右边的name是当前python文件名字空间的变量。

2. 模板变量

2.1 变量格式

在上面例子中看到变量在模板中的写法是这样的:

{{var}}

对于变量的类型,是支持所有的类型,甚至复杂类型。复杂类型指列表,字典和对象。

所有的变量都包含在 {{}} 中,变量的书写方式和python中的相同

<p>字典中的某个值:{{ mydict['key']}}</p>
<p>列表中的某个值:{{ mylist[3]}}</p>
<p>列表中的某个值,index是变量:{{ mylist[myintvar]}}</p>
<p>某个对象的方法,返回的值:{{ myobj.somemethod()}}</p>

2.2 变量过滤器

模板中的变量可以通过名为过滤器的方式,进一步的加工修改。
举个例子:

Hello, {{ name|capitalize}}

其中capitalize是一个过滤器,作用是把name的首字母换成大写字母,其他字母换成小写字母。
过滤器的格式是变量名后加 “|” 再加过滤器。

Jinjia2过滤器列表

过滤器 说明
safe 渲染时不转义
capitalize 首字母大写,其他字母小写
lower 转成小写形式
upper 转成大写形式
title 每个单词的首字母都转成大写
trim 首尾空格去掉
striptags 把值中所有的HTML标签都删掉

转义
Jinji2处理变量的时候,本质上就是交给Python处理双层花括号里边的内容。
这样的话就涉及到双层花括号里的内容,是不是需要转义。
- 转义,就是我只要字符串,字符串什么意思我不关心
- 不转义,就是字符串如果是有含义的,那么需要解析和执行

这是一个例子:

render_template('user.html', name = '<h1>Hello</h1>')

如果user.html模板中,变量name没有使用过滤器,那么以上代码渲染后的页面是经过转义的
image

如果user.html模板中,变量name使用了safe过滤器,那么渲染后的页面,是不转义的:

image

字符串中的h1是经过解析的,header标签生效,这就是所谓的不转义。

不要在不可信的值上使用safe过滤器,这样的不转义,可能执行恶意的脚本,比如打印一个私密的文件之类的。

2.3 控制结构

Jinjia2模板渲染结构是可以通过控制结构,来控制流程的。

注意,所谓的控制结构,都是指模板文件中的代码,不是python中的。

2.3.1 条件 if

修改user.html:

{% if name != 'test' %}
    <h1>Hello, {{ name }}</h1>
{% else %}
    <h1>Hello, this is a test</h1>
{% endif %}

这样如果URL是 …/user/test,会显示 Hello, this is a test,否则会问候用户名字符串。

2.3.2 循环 for

修改user.html:

<ul>
    {% for comment in comments %}
        <li>{{ comment }}</li>
    {% endfor %}
</ul>

这样hello.py也修改一下:

@app.route('/user/<name>')
def user(name):
    namelist = list(name)
    return render_template('user.html', comments = namelist)

通过http://xx.xx.xx.xx:80/user/abc,返回的页面是:
image

2.3.3 宏

类似于函数,可以把常用的部分提取出来形成公共的宏。
比如下面的宏定义:

{% macro li_comment(comment) %}
    <li>{{ comment }}</li>
{% endmacro %}

这就类似于一个带参数的函数了,使用的时候这样:

<ul>
    {% for comment in comments %}
        {{ li_comment(comment) }}
    {% endfor%}
</ul>

如果把各种宏集中在一起,放在一个html文件里,就可以通过导入的方式,在其他的html文件中使用:

{% include 'common.html' %}
{{ li_comment(comment)}}
或者
{% import 'macro.html' as macros %}
{{ macro.li_comment(comment)}}

2.3.4 模板继承

为了维护方便,还有一个办法是使用模板html文件,其他html文件从这个模板文件继承,希望保留的继续保留,想要修改的进行修改。
例子,模板文件base.html:

<html>
<head>
    {{% block head %}}
        <title>
            {{% block title %}}{{% endblock %}} - My Application
        </title>
    {{% endblock%}}
</head>
<body>
    {{% block body %}}
    {{% endblock %}}
</body>

看上面这个模板文件,可以替换的部分是一个一个的block,而且可以嵌套:
- block head
- block title
- block body

模板中有这3个block,可以被继承者修改。比如下面这个衍生出来的html文件:

{% extends "base.html" %}
{% block title %}Index{% endblock%}
{% block head %}
    {{ super() }}
    <style>
    </style>
{% endblock %}
{% block body%}
    <h1>Hello world!</h1>
{% endblock %}

这个衍生文件,通过extends表明继承自base.html,然后分别对base.html中的可变部分进行重新赋值,这样衍生者只关心可变部分的值即可,其他部分沿用父类base.html的内容。

猜你喜欢

转载自blog.csdn.net/guanchunsheng/article/details/79093803