第三章 Flask day2

局部模板

在Web程序中,我们通常会为每一类页面编写一个独立的模板。比如主页模板、用户资料页模板、设置页模板等。
这些模板可以直接在视图函数中渲染并作为HTML响应主体。除了这类模板,我们还会用到另一类非独立模板,这类模板通常被称为局部模板或次模板,因为它们仅包含部分代码,所以我们不会在视图函数中直接渲染它,而是插入到其他独立模板中。
当多个独立模板中都会使用同一块HTML代码时,我们可以把这部分代码抽离出来,存储到局部模板中。这样一方面可以避免重复,另一方面也可以方便统一管理。

比如,多个页面中都要在页面顶部显示一个提示条,这个横幅可以定义在局部模板_banner.html中。
我们使用include标签来插入一个局部模板,这会把局部模板的全部内容插在使用include标签的位置。比如,在其他模板中,我们可以在任意位置使用下面的代码插入_banner.html的内容:

{% include '_banner.html' %}

宏(macro)是Jinja2提供的一个非常有用的特性,它类似Python中的函数。使用宏可以把一部分模板代码封装到宏里,使用传递的参数来构建内容,最后返回构建后的内容。
为了便于管理,我们可以把宏存储在单独的文件中,这个文件通常命名为macros.html或_macors.html。
在创建宏时,我们使用macro和 endmacro标签声明宏的开始和结束。

{% macro qux(amount=1) %}
	{% if amount == 1 %} 
		I am qux.
	{% elif amount > 1 %} 
		We are quxs. 
	{% endif %}
{% endmacro %}

使用时,需要像从Python模块中导入函数一样使用import语句导入它,然后作为函数调用,传入必要的参数

{% from 'macros.html' import qux %} 
... 
{{ qux(amount=5) }}

模板继承

Jinja2的模板继承允许你定义一个基模板,把网页上的导航栏、页脚等通用内容放在基模板中,而每一个继承基模板的子模板在被渲染时都会自动包含这些部分。使用这种方式可以避免在多个模板中编写重复的代码。

子模板追加

如果想要向基模板中的块追加内容,需要使用Jinja2提供的 super()函数进行声明,这会向父块添加内容。
比如,下面的示例向基模板中的styles块追加了一行

{% block styles %}
{{ super() }}
<style>
	.foo {
		color: red;
	}
</style>
{% endblock %}

实践:编写基模板

先写一个模板:base.html

{# 这个基模板中,创建了六个块,
head、title、styles、 content、footer和scripts,分别用来划分不同的代码
其中,head块表示 <head>标签的内容,
title表示<title>标签的内容,
content块表示页面主体内容,
footer表示页脚部分,
styles块和scripts块,则分别用来包含CSS文件和JavaScript文件引用链接或页内的CSS和JavaScript代码#}
<!DOCTYPE html>
<html>
<head>
    {# 模板中由”{% block block_name %}”和”{% endblock %}”所包括的语句块,
    将会替换父模板中同样由”{% block block_name %}”和”{% endblock %}”所包括的语句块。 #}
	{% block head %}
		<meta charset="utf-8">
		<title>{% block title %}Template - HelloFlask{% endblock %}</title>
	   {% block styles %}{% endblock %}
	{% endblock %}
</head>
<body>
<nav>
    {# <ul> 标签定义无序列表。 #}
	<ul><li><a href="{{ url_for('index') }}">Home</a></li></ul>
</nav>
<main>
	{% block content %}{% endblock %}
</main>
<footer>
	{% block footer %}
	 ...
	{% endblock %}
</footer>
{% block scripts %}{% endblock %}
</body>
</html>

以content块为例,继承的模块如图
在这里插入图片描述

编写一个子模板:index.html

{# 指的是继承了base.html #}
{% extends 'base.html' %}
{# 调用宏 导入 #}
{% from 'macros.html' import qux %}
{# 对flask里的content块进行渲染 #}
{% block content %}
{% set name='baz' %}
<h1>Template</h1>
<ul>
    <li><a href="{{ url_for('watchlist') }}">Watchlist</a></li>
    <li>Filter: {{ foo|musical }}</li>
    <li>Global: {{ bar() }}</li>
    <li>Test: {% if name is baz %}I am baz.{% endif %}</li>
    <li>Macro: {{ qux(amount=5) }}</li>
</ul>
{% endblock %}

书上遗漏的点

  1. <li>Filter: {{ foo|musical }}</li> musical未找到
    musical是自定义的过滤器,过滤器函数接收s作为被过滤的变量值,返回处理后的值。
    创建的musical过滤器会在被过滤的变量字符后面添加一个音符(single bar note)图标,音符通过HTML 实体&#9835;表示,我们使用Markup类将它标记为安全字符(将文本标记为安全的一种方法是在渲染前将变量转换为Markup对象)
@app.template_filter()
def musical(s):
    return s+Markup(' &#9835; ')

在这里插入图片描述
错误:未在app.jinja_env.tests里添加自定义测试器
测试器:和过滤器十分相似,区别在于测试器总是返回一个布尔值,它可以用来测试一个变量或者表达式
解决方法:添加代码

def baz(n):
    if n == 'baz':
        return True
    return False
app.jinja_env.tests['baz'] = baz
  1. 未编写宏html
    在这里插入图片描述
    宏(macro)是Jinja2提供的一个非常有用的特性,它类似Python中的函数。使用宏可以把一部分模板代码封装到宏里,使用传递的参数来构建内容,最后返回构建后的内容。
    在功能上,它和局部模板类似,都是为了方便代码块的重用。
    解决办法:新建一个macros.html 附上代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% macro qux(amount=1) %}
    {% if amount == 1 %}
        I am qux.
    {% elif amount > 1 %}
        We are quxs.
    {% endif %}
{% endmacro %}
</body>
</html>

调用的时候输入<li>Macro: {{ qux(amount=5) }}</li>即可

  1. 未注册watchlist.html

重新写一个watchlist.html 再在app.py里加上

user = {
	'username': 'Grey Li',
	'bio': 'A boy who loves movies and music.',
}
movies = [
	{'name': 'My Neighbor Totoro', 'year': '1988'},
	{'name': 'Three Colours trilogy', 'year': '1993'},
	{'name': 'Forrest Gump', 'year': '1994'},
	{'name': 'Perfect Blue', 'year': '1997'},
	{'name': 'The Matrix', 'year': '1999'},
	{'name': 'Memento', 'year': '2000'},
	{'name': 'The Bucket list', 'year': '2007'},
	{'name': 'Black Swan', 'year': '2010'},
	{'name': 'Gone Girl', 'year': '2014'},
	{'name': 'CoCo', 'year': '2017'},
]
@app.route('/watchlist')
def watchlist():
    return render_template('watchlist.html',user=user,movies=movies)
  1. 未注册全局函数和全局对象
def bar(): 
	return 'I am bar.' 
foo = 'I am foo.' 
app.jinja_env.globals['bar'] = bar 
app.jinja_env.globals['foo'] = foo

app.py代码

from flask import Flask,render_template
from flask import Markup
app = Flask(__name__)
user = {
	'username': 'Grey Li',
	'bio': 'A boy who loves movies and music.',
}
movies = [
	{'name': 'My Neighbor Totoro', 'year': '1988'},
	{'name': 'Three Colours trilogy', 'year': '1993'},
	{'name': 'Forrest Gump', 'year': '1994'},
	{'name': 'Perfect Blue', 'year': '1997'},
	{'name': 'The Matrix', 'year': '1999'},
	{'name': 'Memento', 'year': '2000'},
	{'name': 'The Bucket list', 'year': '2007'},
	{'name': 'Black Swan', 'year': '2010'},
	{'name': 'Gone Girl', 'year': '2014'},
	{'name': 'CoCo', 'year': '2017'},
]

def baz(n):
    if n == 'baz':
        return True
    return False
app.jinja_env.tests['baz'] = baz

def bar():
	return 'I am bar.'
foo = 'I am foo.'
app.jinja_env.globals['bar'] = bar
app.jinja_env.globals['foo'] = foo

@app.template_filter()
def musical(s):
    return s+Markup(' &#9835; ')

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/watchlist')
def watchlist():
    return render_template('watchlist.html',user=user,movies=movies)
if __name__ == '__main__':
    app.run()

渲染子模板

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Template - HelloFlask</title>
</head>
<body>
<nav>
	<ul><li><a href="/">Home</a></li></ul></nav> 
<main> 
<h1>Template</h1> 
<ul>
	<li><a href="/watchlist">Watchlist</a></li>
	<li>Filter: I am foo. &#9835;</li> 
	<li>Global: I am bar.</li> 
	<li>Test: I am baz.</li> 
	<li>Macro: We are quxs.</li>
</ul>
</main> 
<footer>
 ... 
</footer> 
</body> 
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值