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()渲染模板4,运行项目
当然,动态模板才是最常见的,即多是情况下我们是需要将一些内容传递给模板进行渲染使用的。
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: ```html @app.route('/<sex>') 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: ```html @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的引入,使得网页具有更丰富的内容与交互方式,它们将让用户获得更好的使用体验。
除了直接在模板文件中使用<script>标签包含静态内容,更推荐的方法是将它们统一放入static文件中。项目结构如下:
模板:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {# <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 %}中添加自己的内容。
项目结构如下: 父模板base.html:
<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() }}保留父模板内容