Python jinja2 基础知识
@
jinja2原理
Flask 的render_template默认使用了jinja2的模板引擎渲染页面
demo.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def demo():
return render_template('demo.html')
if __name__ == '__main__':
app.run(debug=True)
templates/demo.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>你好,</h1>
</body>
</html>
渲染出的html是这样的
![](https://img2023.cnblogs.com/blog/2119256/202308/2119256-20230811091255182-1147530768.png)
这和下面的代码的效果没有什么区别
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def demo():
html = """"
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>你好,</h1>
</body>
</html>
"""
return html
if __name__ == '__main__':
app.run(debug=True)
而且也能传参数
demo.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def demo():
with open('templates/demo.html', 'r', encoding='utf-8') as file:
html = file.read()
html = html.replace('{{ your_name }}', 'pineapple')
return html
if __name__ == '__main__':
app.run(debug=True)
templates/demo.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>你好,{{ your_name }}</h1>
</body>
</html>
渲染结果如下所示:
![在这里插入图片描述](https://img2023.cnblogs.com/blog/2119256/202308/2119256-20230811091255137-267499987.png)
这样就简单实现了前端html和后端python代码的交互,这就是jinja2和其他一些模板引擎的原理!
jinja2基本语法
-
{% ...%}
用于循环或判断语句。 -
{{...}}
用于表达式的值的引用。 -
{# ...#}
用于模板引擎的注释,如果注释中存在模板引擎的语法,那么使用将不被模板引擎认为是注释,注释中的语法将被执行。此时请使用{##}进行注释。
普通传值
语法:{{ python表达式 }}
templates/demo.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
div {
width: 400px;
height: 200px;
border: solid 2px red;
text-align: center;
padding: 20px;
line-height: 40px
}
</style>
</head>
<body>
<div>
<span>你的登录账号为:{{ session.get('username') }}</span><br>
<span>这篇文章的标题:{{ article.title }}</span><br>
<span>文章的阅读次数:{{ article.count + 1 }}</span><br>
</div>
</body>
</html>
demo.py
import os
from flask import Flask, render_template, session
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
@app.route('/')
def demo():
session['username'] = 'Pineapple'
article = {
'title': 'Flask jinja2模板',
'count': 9999
}
return render_template('demo.html', session=session, article=article)
if __name__ == '__main__':
app.run(debug=True)
渲染结果:
![在这里插入图片描述](https://img2023.cnblogs.com/blog/2119256/202308/2119256-20230811091254918-2083254883.png)
jinja2的模板里,字典可以用dict.key的方式获取值
条件语句
语法
{% if %}
{% elif %}
{% else %}
{% endif %}
templates/demo.html继续添加
{% if article.count % 2 == 0 %}
<span>{{ article.count }}可以被2整除,是个偶数</span>
{% else %}
<span>{{ article.count }}不可以可以被2整除,是个奇数</span>
{% endif %}
![在这里插入图片描述](https://img2023.cnblogs.com/blog/2119256/202308/2119256-20230811091255122-1898039074.png)
循环语句
语法
{% for %}
{% endfor %}
templates/demo.html继续添加
{% for i in range(5) %}
<span>第{{ i }}次</span><br>
{% endfor %}
![在这里插入图片描述](https://img2023.cnblogs.com/blog/2119256/202308/2119256-20230811091255120-655989780.png)
初始化变量
在jinja2模板中,用set
关键字初始化变量
{% set loop = 6 %}
{% for i in range(loop) %}
<span>第{{ i }}次</span><br>
{% endfor %}
![在这里插入图片描述](https://img2023.cnblogs.com/blog/2119256/202308/2119256-20230811091255008-1987283794.png)
过滤器
https://jinja.palletsprojects.com/en/2.11.x/templates/#id11
https://jinja.palletsprojects.com/en/2.11.x/templates/#list-of-builtin-filters
过滤器其实就是函数,以 | 分割,左边的输出作为右边过滤器的参数输入,有点类似于Linux的管道
内置过滤器
![在这里插入图片描述](https://img2023.cnblogs.com/blog/2119256/202308/2119256-20230811091255165-1010847541.png)
举几个栗子
safe
safe
(value)
将值标记为安全,这意味着在具有自动转义启用后,此变量将不会被转义。
先看看不加safe
templates/demo.html 添加
{{ red_font }}
demo.py 添加
red_font = """
<span style="color: red">这是一段红色的字</span>
"""
return render_template('demo.html', session=session, article=article, red_font=red_font)
可以看到它是以普通字符串的形式展示在页面上的
![](https://img2023.cnblogs.com/blog/2119256/202308/2119256-20230811091255151-1360413015.png)
加上过滤器后
{{ red_font | safe }}
![](https://img2023.cnblogs.com/blog/2119256/202308/2119256-20230811091254934-1286206084.png)
所以这个safe还是很有用地,之后向 Echarts js传数据也会用到它
truncate
truncate
(s, length=255, killwords=False, end='...', leeway=None)
返回字符串的截断
副本。 长度已指定 第一个参数默认为 255
。 如果第二参数是 true
过滤器将剪切文本的长度。 除此以外 它将丢弃最后一个单词。 如果文字是事实截断后会附加省略号( "..."
)。 如果你想要一个 与 省略号不同的省略号 "..."
您可以使用的 第三个参数。 仅超出长度公差的字符串 第四个参数中给出的空白将不被截断。
{{ "foo bar baz qux"|truncate(9) }}
-> "foo..."
{{ "foo bar baz qux"|truncate(9, True) }}
-> "foo ba..."
{{ "foo bar baz qux"|truncate(11) }}
-> "foo bar baz qux"
{{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
-> "foo bar..."
如果killwords=True,那么返回的字符串的长度为指定的长度 + end长度:length + len(end)
这个truncate还是挺复杂的,不明白老外为啥非得这么搞,就不能像python里的切片一样吗?
更详细的解释请看这位同志:https://blog.csdn.net/yueguangmanong/article/details/85196199
调用自定义函数
在模板中调用python中的函数,主要又两种方法
装饰器
使用上下文处理器context_processor
这种调用方式,准确的说不是调用函数,而是调用返回值的参数,且返回值必须是字典形式,也可以说是json格式
dem.py
@app.context_processor
def func():
result1 = {'1': 'Python', '2': 'Linux', '3': 'Java'}
result2 = [1, 2, 3, 4, 5, 6]
return dict(result1=result1, result2=result2)
templates/demo.html
{{ result1 }}
{{ result2 }}
{{ result1['1'] }}
渲染结果
这种方式如果想要传参,得使用两层闭包
demo.py
@app.context_processor
def func():
def func1(args1):
result = {'1': 'Python', '2': 'Linux', '3': 'Java'}
return result[args1]
return dict(func1=func1)
tmeplates/demo.html
{{ func1('1') }}
渲染结果
全局注册
在全局jinja_env中注册自定义函数
demo.py
def func():
result = {'1': 'Python', '2': 'Linux', '3': 'Java'}
return result
app.jinja_env.globals.update(func=func)
templates/demo.html
{{ func() }}
注意这时是要加小括号()的,不然得到的将是函数的地址,而不是调用函数
渲染结果
这种方式的话,传参数会变得简单些
def func(args):
result = {'1': 'Python', '2': 'Linux', '3': 'Java'}
return result[args]
app.jinja_env.globals.update(func=func)
{{ func('2') }}
渲染结果
调用自定义过滤器
过滤器其实就是一种特殊的函数,将|前的值作为|后的函数第一个参数,函数返回值为最终结果
也是有两个方法,不过都大差不差
装饰器
调用模板过滤器template_filter,参数为过滤器名,和函数名并无关系
demo.py
@app.template_filter('my_len')
def my_len(s):
return len(s)
templates/demo.html
{{ "Hello, how are you ? " | my_len }}
渲染结果
全局注册
与自定义函数一样,同样是注册到jinja_env里
def my_len(s):
return len(s)
app.jinja_env.filters.update(my_len=my_len)
渲染结果和上面一样,不演示了。