⭐ 简介:大家好,我是zy阿二,我是一名对知识充满渴望的自由职业者。
☘️ 最近我沉溺于Python的学习中。你所看到的是我的学习笔记。
❤️ 如果对你有帮助,请关注、点赞,让我们共同进步。有不足之处请留言指正!
1. Flask打造 Python Web 开发的灵活框架,实现简易登录。入门篇
2. Flask中默认集成了Jinja2,用于web应用程序中生成动态内容。进阶篇【本文】
# 前言
Jinja2是一个流行的HTML引擎,用于在Flask等Python Web应用程序中生成HTML,XML或其他文本格式的动态内容。Flask中默认集成了Jinja2。
Jinja2允许开发人员将动态内容与静态HTML代码分离。通过在HTML中使用Jinja2语法,可以将动态内容以一种可读性强且易于维护的方式与HTML混合在一起。Jinja2还支持过滤器,控制结构和继承等高级功能。
在Flask中,可以通过将Jinja2模板存储在应用程序的“templates”目录中,并使用Flask的内置render_template函数将模板渲染为响应发送给客户端。例如,在Flask应用程序中渲染一个名为“index.html”的模板的代码如下:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html', name='World')
if __name__ == '__main__':
app.run()
在此示例中,应用程序使用render_template函数渲染了“index.html”,并将参数“name”设置为“World”。在模板中,可以使用Jinja2语法来访问该参数,例如:
<!DOCTYPE html>
<html>
<head>
{# 我是注释 #}
<title>Hello {{ name }}!</title>
</head>
<body>
{# 我是注释 #}
<h1>Hello {{ name }}!</h1>
</body>
</html>
在这个例子中
- 使用
{{ name }}
语法来引用传递给它的参数“name”,从实现不同用户显示不同的HTML内容。(即:动态HTML内容) - 同时
{# 我是注释 #}
是Jinja2注释的格式。
1. Jinja2的for循环示例
当我们想要根据列表、字典或其他可迭代对象在HTML上生成一个列表时,我们就可以这样做。
下面我们创建了一个名为 "my_list.html " 的文件,并写入内容如下:
<!DOCTYPE html>
<html>
<head>
<title>My List</title>
</head>
<body>
<h1>My List</h1>
<ul>
{% for item in my_list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</body>
</html>
假设一个名为 “my_list” 的Python列表,在模板中使用for循环来遍历这个列表,并使用{{ item }}
在每个项目之前创建一个HTML列表项。
为了在Flask应用程序中使用此模板,我们可以使用"render_template"函数并将"my_list"作为参数传递给模板。例如:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
my_list = ['item 1', 'item 2', 'item 3']
return render_template('my_list.html', my_list=my_list)
if __name__ == '__main__':
app.run()
运行并打开后将得到如下页面:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z9xnvGLo-1677990858750)(C:\Users\张义\AppData\Roaming\Typora\typora-user-images\image-20230305122742840.png)]
当然,我们可以通过修改 ”my_list“ 中的内容来实现更加丰富的动态页面。
值得注意的是 :
-
{{ item }}
在Jinja2中引用变量需要2个花括号包裹。如需引用多个,每一个变量都需要2个花括号包裹。例如{{ item1 }}{{ item2 }}
-
for循环也有严格的格式
{% for ... in .... %}
而且{% endfor %}
也是必须的。表示for循环代码结束的位置,循环的内容则写在中间。 -
Jinja2的for循环是直接完成的,它不同于Python还有
break
方法来提前中断循环。
{% for item in my_list %}
<li>{{ item }}</li>
{% endfor %}
2. Jinja2的for循环生成表格示例
假设 my_list 是一个二维数组,每个值中包含,书名,作者,价格和日期。根据my_list 生成一个带有表格的HTML页面。
“my_list.html” 文件内容如下:
<!DOCTYPE html>
<html>
<head>
<title>Book List</title>
<!-- 为了使得表格看上去美观一点,我引入了bootstrap。虽然可以使用原生CSS美化,但是会让代码变得太长,不适合演示。不懂bootstrap的可以选择性的屏蔽掉所有的class 或者直接删除下方的link标签-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>Book List</h1>
<table class="table table-bordered table-striped">
<thead class="thead-dark">
<tr>
<th scope="col">Book</th>
<th scope="col">Author</th>
<th scope="col">Price</th>
<th scope="col">Date</th>
</tr>
</thead>
<tbody>
{% for row in my_list %}
<tr>
<td>{{ row[0] }}</td>
<td>{{ row[1] }}</td>
<td>{{ row[2] }}</td>
<td>{{ row[3] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
</html>
py文件内容如下:
from flask import Flask, render_template
app = Flask(__name__)
# 运行代码后访问: `http://localhost:5000`
@app.route('/')
def index():
my_list = [['Book 1', 'Author 1', 19.99, '2020-01-01'],
['Book 2', 'Author 2', 29.99, '2021-02-02'],
['Book 3', 'Author 3', 39.99, '2022-03-03'],
['Book 4', 'Author 4', 49.99, '2023-04-04'],
['Book 5', 'Author 5', 59.99, '2024-05-05']]
return render_template('my_list.html', my_list=my_list)
if __name__ == '__main__':
app.run()
运行代码后访问: http://localhost:5000
,得到如下页面:
3. Jinja2的if 判断
- if语句的语法结构:
{% if .... %}
…
{% elif ... %}
…
{% endif %}
- 值得注意的还是
{%..%}
的结构和必须在if结束的位置加上{% endif %}
- 延用上一条中的书本Book List的py数据。
这次我们在循环内加上了if语句做条件判断,如果价格小于20,就给这一行加上黄色背景,如果价格大于40,就给这一行加上红色背景,否则就不加背景。这里的row[2]就是价格,row[0]是书名,row[1]是作者,row[3]是日期。
<!DOCTYPE html>
<html>
<head>
<title>Book List</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>Book List</h1>
<div class="table-responsive">
<table class="table table-hover">
<thead class="thead-light">
<tr>
<th scope="col">Book</th>
<th scope="col">Author</th>
<th scope="col">Price</th>
<th scope="col">Date</th>
</tr>
</thead>
<tbody>
{% for row in my_list %}
<!-- 这次我们在循环内加上了if语句做条件判断,如果价格小于20,就给这一行加上黄色背景,如果价格大于40,就给这一行加上红色背景,否则就不加背景。这里的row[2]就是价格,row[0]是书名,row[1]是作者,row[3]是日期。 -->
{% if row[2] < 20 %} <tr style="background-color: yellow;">
{% elif row[2] > 40 %}
<tr style="background-color: red;">
{% else %}
<tr>
{% endif %}
<td>{{ row[0] }}</td>
<td>{{ row[1] }}</td>
<td>{{ row[2] }}</td>
<td>{{ row[3] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</body>
</html>
执行代码后,访问: http://localhost:5000
得到如下页面
3. if判断简单示例
首先创建一个“index.html” 写入代码:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
{% if user %}
<h1>欢迎你, {{ user.username }}!</h1>
{% else %}
<h1>欢迎来宾!</h1>
{% endif %}
</body>
</html>
在上面的html文件中,使用双花括号“{{}}”插入变量和使用“{% %}”控制流,如果有user,则显示欢迎用户的消息,否则显示欢迎来宾的消息。其中,user和title是在Flask应用程序中定义的变量。
然后在py文件中写入:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
user = {'username': 'John'}
return render_template('index.html', title='Home', user=user)
if __name__ == "__main__":
app.run(debug=True)
5. Jinja2的 extends
- 语法结构:
{% block name %} ... {% endblock %}
{% block %}
是 Jinja2 模板引擎的一个核心功能,它允许您定义一个模板块,该模板块可以在子模板中被重写和填充。类似python中的class封装一些固定的方法,减少代码的重用率。
具体来说,{% block %}
标记定义了一个命名的模板块,可以将该模板块视为一个占位符。在父模板中,该模板块可能包含一些默认内容,但是在子模板中,该模板块可以被重写,并且将显示子模板中的新内容。以下是一个简单的示例:
首先创建一个base.html
模版:
<!DOCTYPE html>
<html>
<head>
<title>{% block title %} base.html 模版的title {% endblock %}</title>
</head>
<body>
<div class="header">
{% block header %} base.html 模版的 Header{% endblock %}
</div>
<div class="content">
{% block content %} base.html 模版的 Content{% endblock %}
</div>
<div class="footer">
{% block footer %} base.html 模版的 Footer{% endblock %}
</div>
</body>
</html>
再创建一个home.html
模版:
{% extends 'base.html' %}
{% block title %}
主页
{% endblock %}
{% block header %}
<h1>欢迎来到我的主页</h1>
{% endblock %}
{% block content %}
<p>我是一个有理想有目标有远见有卓越智慧的肉肉!!</p>
{% endblock %}
在home.html
模板中,我们继承了 base.html
模板,并重写了 title
、header
和 content
中的内容,以创建一个和 base.html
结构相同但是内容却不一样的主页。就像是python中创建一个类,继承另一个类,又重写了父类方法。
再创建一个about.html
模板:
{% extends 'base.html' %}
{% block title %}
关于我
{% endblock %}
{% block header %}
<h1>我的简介</h1>
{% endblock %}
{% block content %}
<p>我是一盒坚持学习不断进取的猪肉!!</p>
{% endblock %}
新的about.html
模板,我们又继承了 base.html
模板,并再次重写了 title
、header
和 content
中的内容,所以这3个模版的HTML结构都是相同的,但是其中的内容是不同的。
最后,我们创建一个py文件,代码如下:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
return render_template('home.html')
@app.route('/about')
def about():
return render_template('about.html')
if __name__ == '__main__':
app.run(debug=True)
运行,然后访问 http://localhost:5000
和 http://localhost:5000/about
,以查看生成的 HTML 页面。
最后你可以自己尝试重新修改以下“ base.html 模版的 Footer ”的内容。
总结: {% block name %} ... {% endblock %}
的目的就是为了减少代码的重用率。
6. Jinja2的 macro name(args)
- 既然有类就有函数。语法结构:
{% macro macro(args) %}
…{% endmacro %}
定义一个函数
定义一个可重用的模板块,称为“宏”(Macro)。 它类似于一个函数,接受一个或多个参数,可以在模板中多次调用,以避免重复编写相同的代码。宏可以带有参数,这些参数可以在宏内部使用,用于生成特定的输出。类是于python中的 def macro(*arg):
在函数内部执行完成后通过return
输出结果。
例如,以下代码定义了一个名为 hello
的宏,它带有一个参数 name
,并在模板中使用了调用了他3次:
{% macro hello(name) %}
<h1>你好我好大家好,我是 {{ name }}!</h1>
{% endmacro %}
{{ hello('John') }}
{{ hello('Binbin') }}
{{ hello('Liya') }}
下面是一个完整的 Flask 和 Jinja2 模板的示例。
首先创建一个“index.html” 写入代码:
<!DOCTYPE html>
<html>
<head>
<title>Hello World</title>
</head>
<body>
{% macro hello(name) %}
<h1>你好我好大家好,我是 {{ name }}!</h1>
{% endmacro %}
{{ hello('John') }}
{{ hello('Binbin') }}
{{ hello('Liya') }}
</body>
</html>
py文件代码如下:
from flask import Flask, render_template
from jinja2 import Template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True)
执行代码后,访问 http://localhost:5000
后得到如下页面:
在这个示例中,我们定义了一个hello
宏,并调用了他3次,返回了3个带有固定字符串“你好我好大家好,我是 ”和自定义name的3个h1标签。实现了简单的避免代码重用的方法。