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
  1. 嵌入/行内式js/css
    难以维护,跳过。
  2. 定义为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);
}

当然还有很多其他办法。