flask 使用 Jinja2 引擎来渲染模板。
简单来说,在web应用开发中,后端主要负责业务逻辑,完成请求与响应的逻辑处理及数据读写,前端主要负责表现逻辑,完成应用界面表现与交互逻辑。为了实现前后端的解耦,分离前后端逻辑,就可以将表现逻辑分离出来交由模板通过模板引擎渲染来实现。
这样看来,其实模板就是包含静态与动态内容的网页内容。
Jinja 是一种现代的、对设计人员友好的 Python 模板语言。它具有快速、广泛使用和安全的特性,并且具有可选的沙箱模板执行环境。
所谓渲染,其实就是向网页中加载静态内容及动态内容值的过程。
下面是一个最简单的例子:
1,创建flask项目
这里以创建flask项目:Hello,Flask!为例。
2,在项目中的 templates 文件中创建 .html 文件
应用结构及 .html 内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
3,编写路由及试图处理函数
app.py内容如下:
from flask import Flask
from flask import render_template
@app.route('/')
def hello_world():
return render_template('index.html')
if __name__ == '__main__':
app.run()
render_template()
渲染模板当然,动态模板才是最常见的,即多是情况下我们是需要将一些内容传递给模板进行渲染使用的。
app.py:
@app.route('/')
def hello_world():
content = "首页内容"
return render_template('index.html', content=content)
index.html:
<body>
<h1>{{ content }}h1>
body>
{{ var }}
使用传来的参数值。app.py:
@app.route('/')
def hello_world():
title = "首页"
content = "首页内容"
return render_template('index.html',
content=content,
title=title)
index.html:
<head>
<meta charset="UTF-8">
<title>{{ title }}title>
head>
<body>
<h1>{{ content }}h1>
body>
上面的方法确实可以向模板传递多个参数,但是太麻烦了, flask 还有另一种方法。
app.py:
@app.route('/')
def hello_world():
title = "首页"
content = "首页内容"
return render_template('index.html', **locals())
**locals()
将所有参数传递给了模板,然后选择性使用。效果与2是一样的,
详细的模板语法请参考Jinja2官方文档,这里只作简单介绍。
在上面的模板中我们看到了一些不同于html原生语法的东西:{{ var }}
{{ }}
这东西叫分隔符,模板语法中的分隔符有好几个:
{% ... %}
用于声明,比如在使用for控制语句时
{{ ... }}
用于打印到模板输出的表达式,比如之前传到到的变量(更准确的叫模板上下文)
{# ... #}
用于模板注释
# ... ##
用于行语句,就是对语法的简化
模板语法:
{% if condition %}
do_something
{% elif condition %}
do_something
{% else %}
do_something
{% endif %}```
app.py:
@app.route('/' )
def hello_world(sex):
title = "首页"
content = sex
return render_template('index.html', **locals())
index.html:
<body>
{% if content == "男" %}
<h1>男h1>
{% elif content == "女" %}
<h1>女h1>
{% else %}
<h1>性别未知h1>
{% endif %}
body>
语法:
{% for item in iteratable_object %}
do_something
{% endfor %}
app.py:
@app.route('/')
def hello_world():
title = "首页"
content = [
{'name': '张三', 'age': 10},
{'name': '李四', 'age': 11},
{'name': '王五', 'age': 12},
]
return render_template('index.html', **locals())
模板:
<body>
<h1>人员信息:h1>
{% for info in content %}
<span>{{ info.name }} {{ info.age }}span>
<br>
{% endfor %}
body>
变量可以通过过滤器修改。 过滤器由竖线符号 |
与变量分开,并且括号中可以包含可选参数。 可以链接多个过滤器。 一个滤波器的输出将应用于下一个。
flask 提供了许多内建过滤器。
模板:
<body>
<h1>人员信息:h1>
{%for info in content|sort(attribute="age")|sort(reverse=true,attribute="name")%}
<span>{{ info.name }} {{ info.age }}span>
<br>
{% endfor %}
body>
add_template_filter()
方法添加到模板自定义过滤器如下:
app.py:
@app.route('/')
def hello_world():
title = "首页"
content = [
{'name': '张三', 'age': 10},
{'name': '李四', 'age': 11},
{'name': '王五', 'age': 12},
]
return render_template('index.html', **locals())
def do_add_age_number(age_number):
age = age_number + 3
return age
app.add_template_filter(do_add_age_number, 'add_age_number')
模板:
<body>
<h1>人员信息:h1>
{%for info in content %}
<span>{{ info.name }} : {{ info.age | add_age_number }}span>
<br>
{% endfor %}
body>
宏可与常规编程语言中的功能媲美。 它们有助于将常用的惯用语放入可重复使用的功能中,从而使一个宏可以被多个模板使用。
1,声明与调用
模板:
<body>
<h1>人员信息:h1>
{% macro input(name, value='', type='text', size=20, placeholder="在这里输入内容") -%}
<input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" placeholder="{{ placeholder }}">
{% endmacro %}
<div class="info">
<p>用户:{{ input('username') }}p>
<p>密码:{{ input('password', type='password') }}p>
<p>登录:{{ input(type='submit', value="登录") }}p>
div>
body>
2,规范化使用宏
就像C语言中的头文件概念一样,我们最好将宏统一放置:
使用时再导入:
{% import "macros/login_form.html" as login_form %}
<div class="info">
<p>用户:{{ login_form.input('username') }}p>
<p>密码:{{ login_form.input('password', type='password') }}p>
<p>登录:{{ login_form.input(type='submit', value="登录") }}p>
div>
3,include
include 可以将一个模板导入到指定模板中。
set 与 with 都能在模板中设置变量,前者为全作用域,后者为本标签作用域,这与 DTL 是一样的。
<body>
{% include "included.html" %}
{% set massage="人员信息修改:" %}
<h1>{{ massage }}h1>
{% import "macros/login_form.html" as login_form %}
{% with warning="注意保管系统管理员密保卡内容!" %}
<div class="info">
<p>用户:{{ login_form.input('username') }}p>
<p>密码:{{ login_form.input('password', type='password') }}p>
<p>登录:{{ login_form.input(type='submit', value="登录") }}p>
div>
<div class="warning">
<span>{{ warning }}span>
div>
{% endwith %}
body>
css 与 JavaScript 的引入,使得网页具有更丰富的内容与交互方式,它们将让用户获得更好的使用体验。
除了直接在模板文件中使用\
标签包含静态内容,更推荐的方法是将它们统一放入 static 文件中。项目结构如下:
模板:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
{# <script src="{{ url_for('static', filename='js/jquery-3.3.1/jquery-3.3.1.js') }}">script>#}
<script type="text/javascript" src="static/js/jquery-3.3.1/jquery-3.3.1.js">script>
<link rel="stylesheet" href="{{ url_for('static',filename='css/car.css') }}">
head>
<body>
{#测试jquery是否加载#}
<script>
if(jQuery) {
alert('jQuery已加载!');
}
else {
alert('jQuery未加载!');
}
script>
<div class="img">
<img src="{{ url_for('static', filename='images/car.jpg') }}">img>
div>
body>
html>
前面讲的 include
能将一个模板嵌入到另一个模板,模板继承允许一个模板继承另一个模板并进行一些修改。
父模板中添加 {% block partname %}{% endblock %}
就允许子模板对这块内容进行修改。
子模板使用 {% extends %}
继承父模板,并在 {% block partname %}{% endblock %}
中添加自己的内容。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}title>
head>
<body>
{% block body %}
这是父模板中的内容
{% endblock %}
body>
html>
子模板index.html:
{% extends "base.html" %}
{% block title %}网站首页{% endblock %}
{% block body %}
{{ super() }}
<h4>这是子模板的内容!h4>
{% endblock %}
{{ super() }}
保留父模板内容