flask web学习之模板(二)
一、模板结构组织
1.1 局部模板
当多个独立模板中都会使用同一块HTML代码时,我们可以把这部分代码抽离出来,存储到局部模板中。这样,既可以避免重复,也可以方便统一管理。
{% include '_banner.html' %} # 为了和普通模板分开,局部模板的命名通常都以一个下划线开始
1.2 宏
宏是Jinja2提供的一个非常有用的特性,它类似Python的函数。使用宏可以把一部分代码封装到宏里,通过传递的参数来构建内容,最后渲染。
_macros.html
# 在创建宏时,使用macro与endmaccro标签来声明宏。
{ % macro qux(amount) = 1 %}
{% if amount == 1 %}
I am a boy.
{% elif amount >1 %}
I am a girl.
{% endif %}
{%% endmacro %}
使用时,像Python中导入函数一样导入。
{% from '_macros.html' import qux %}
....
{{qux(amount=5)}}
另外在使用宏的时候要注意上下文问题。出于性能的考虑,并且为了让这一切保持显式,默认情况下include一个模板时会传递上下文到局部模板中,但import不会。所以我们需要导入时显式的使用with context来声明传入当前模板的上下文。
1.3 模板继承
Jinja2允许你定义一个基本模板,把网页上的导航栏、页脚等通用内容放在基模板中,而每一个继承模板的子模板都会在渲染时自动包含这些部分。
基模板 base.html
<!DOCTYPE html>
<html>
<head>
{% block head %}
<meta charset="utf-8">
<title>{% block title %} 基模板 {% endblock %}</title>
{% block style %}{% endblock %}
{% endblock %}
</head>
<body>
<header>
<!-- 网站头部内容 -->
</header>
<nav>
<!-- 网站导航栏内容 -->
</nav>
<main>
<!-- 网站主要内容 -->
{% block content %}{% endblock %}
</main>
<footer>
<!-- 网站页脚内容 -->
{% block footer %}
...
{% endblock %}
</footer>
{% block scripts %}{% endblock %}
</body>
</html>
基本模板中块的开始和技术分别使用block和endblock标签俩声明,并且块与块之间可以嵌套。我们只需要在子模板中定义同名的快来执行继承操作。
子模板 index.html
{% extends 'base.html' %}
{from 'macros.html' import qux %}
{% block content %}
{% set name = 'baz' %}
<h1>sdad</h1>
<li>macro:{{ qux{amount=5) )} </li>
{% endblock %}
在子模块中,可以对父模块中的块执行两种操作:
- 覆盖内容:创建同名模块即可。
- 追加内容:需要使用super()函数进行声明。
# 追加内容至base.html 的styles模块
{% block styles %}
{{ super() }}
<style>
.foo{
color: #FFF;
}
</style>
{% endblock %}
二、模板进阶
2.1 空白控制
- 如果想在渲染时去掉模板中的空行,可以在定界符内添加减号。
<div>
{% if True -%}
<p>Hello!</p>
{%- endif %}
- 还有一种办法是使用模板环境对象提供的trin_blocks和lstrip_blocks属性设置,欠着删除Jinja2语句的第一个空行,后者删除Jinja2语句所在行之前的空格和tabs
app.jinja_env.trin_blocks = True
app.jinja_enc.lstrip_blocks = True
需要注意的是宏内的空白控制行为只能用第一种办法设置。
2.2 加载静态文件
- 添加Favicon
<link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}" >
- 使用css框架
{% block styles %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}" >
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='js/jquery.min.js') }}"></script>
{% endblock %}
- 使用宏加载静态资源
<--定义宏-->
{% macro static_file(type, url, loacl=True) %}
{% if local %}
{% set url=url_for('static', filename=url) %}
{% endif %}
{% if type == 'css' %}
<link rel="stylesheet" href="{{ url }}">
{% elif type == 'js' %}
<script src="{{ url }}"></script>
{% endif %}
{% endmacro %}
<--使用宏-->
{% import "static.macros.html" as static %}
{{ static.static_file("css", "/static/css/style.css") }}
{{ static.static_file("js", "/static/js/script.js") }}
2.3 消息闪现
flask提供了一个非常有用的flash()函数,它可以用来闪现需要显示给用户的消息。
# 使用flash“闪现”消息
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
# 模拟用户登录验证
if username == 'admin' and password == 'password':
flash('登录成功!', 'success')
return redirect(url_for('index'))
else:
flash('用户名或密码错误!', 'error')
return render_template('login.html')
# 模板渲染flash消息
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li class="{{ message[1] }}">{{ message[0] }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
2.4 自定义错误页面
flask提供了@app.errorhandler()
装饰器来自定义错误页面。它接收三个参数,code:状态码,name:原因短语,description:错误描述。
@app.errorhandler(404)
def page_not_found(e):
return render_template('error/404.html'), 404
2.5 在js和css中使用Jinja2
- 嵌入/行内式js/css
难以维护,跳过。 - 定义为js/css变量
// script.js
var name = '{{ name }}';
console.log('Hello ' + name + '!');
/* style.css */
:root {
--background-color: {{ bg_color }};
--color: {{ text_color }};
}
#foo {
color: var(--color);
background-color: var(--background-color);
}
当然还有很多其他办法。