flask模板结构组织(局部模板、宏、模板继承)--

模板结构组织

除了使用函数、过滤器等工具控制模板的输出外,jinja2还提供了一些工具来在宏观上组织模板内容。

局部模板

在Web程序中,我们通常会为每一类页面编写一个独立的模板。比如主页模板、用户资料也模板、设置页模板等。这些模板可以直接在视图函数中渲染并作为HTML响应主题。除了这类模板,我们还会用到另一类非独立模板,这类模板通常被称为局部模板或此模板,因为它们仅包含部分代码,所以我们不会在视图函数中直接渲染它,而是插入到其他独立模板中。

当某个视图用来处理ajax请求时,返回的数据不需要包含完整的HTML结构,这时就可以返回渲染后的局部模板。

当多个独立的模板中都会使用同一块HTML代码时,我们可以把这部分代码抽离出来,存储到局部模板中。这样一方面可以避免重复,另一方面也可以方便统一管理。比如,多个页面中都要在页面顶部显示一个提示条,这个横幅可以定义在局部模板_banner.html中。

我们使用include标签来插入一个局部模板,这会把局部模板的全部内容插在使用include标签的位置。

比如在其他模板中,我们可以在任意位置使用下面的代码插入_banner.html的内容:

{% include ‘_banner.html’ %}

为了和普通模板区分开,局部模板的命名通常以一个下划线开始。

宏(macro)是jinja2提供的一个非常有用的特性,它类似python中的函数。使用宏可以把一部分模板代码封装到宏里,使用传递的参数来构建内容,最后返回构建后的内容。在功能上,它和局部模板类似,都是为了方便代码块的重用。

为了便于管理,可以把宏存储在单独的文件中,这个文件通常命名为macros.html或_macros.html。在创建宏时,使用macro和endmacro标签声明宏的开始和结束。在开始标签中定义宏的名称和接收的参数

例子:

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

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

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

另外,在使用宏时我们需要注意上下文问题,在jinja2中,出于性能的考虑,并且为了让一切保持显示,默认情况下包含(include)一个局部模板会传递当前上下文到局部模板中,但导入(import)不会。具体来说,当我们使用render_template()函数渲染一个foo.html模板时,这个foo.html的模板上下文中包含下列对象:

1 flask使用内置的模板上下文处理函数提供的g、session、config、request。

2 扩展使用内置的模板上下文处理函数提供的变量。

3 自定义模板上下文处理传入的变量

4 使用render_template()函数传入的变量

5 jinja2和flask内置及自定义全局对象。

6 jinja2内置及自定义过滤器

7 jinja2内置及自定义测试器

使用include标签插入的局部模板(比如_banner.html)同样可以使用上述上下文中的变量和函数。而导入另一个并非直接渲染的模板(比如macro.html)时,这个模板进包含下列这些对象:

1 jinja2和flask内置的全局函数和自定义全局函数

2 jinja2内置及自定义过滤器

3 jinja2内置及自定义测试器

因此,如果我们想在导入的宏中使用第一个列表中的2、3、4项,就需要在导入时显示地使用with context声明传入当前模板的上下文:

{% from “macros.html” import foo with context %}

虽然flask使用内置的模板上下文处理函数传入session、g、request和config,但它同时也使用app.jinja_env.globals字典将这几个变量设置为全局变量,所以我们仍然可以在不显示声明传入上下文的情况下,直接在导入的宏中使用它们。

模板继承

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

编写基模板

基模板存储了程序页面的固定部分,通常被命名为base.html或layout.html。实例程序中的基模板base.html中包含了一个基本的HTML结构,我们还添加了一个简单的导航条和页脚

<!DOCTYPE html>
<html lang="en">
<head>
    {% block head %}
        <meta charset="utf-8">
        <title>{% block title %}Template - HelloFlask{% endblock %}</title>
        {% block styles %}{% endblock %}
    {% endblock %}
</head>
<body>
<nav>
    <ul><li><a href="{{ url_for('index') }}">Home</a></li></ul>
</nav>
<main>
    {% block content %}{% endblock %}
</main>
<footer>
    {% block footer %}
        ...
    {% endblock %}
</footer>
{% block sripts %}{% endblock %}
</body>
</html>

当子模板继承基模板后,子模板会自动包含基模板的内容和结构。为了能够让子模板方便地覆盖或插入内容到基模板中,我们需要在基模板中定义块(block),在子模板中可以通过定义同名的块来执行继承操作。

块的开始和结束分别使用block和endblock标签声明,而且快之间可以嵌套。在这个基模板中,我们创建了6个块:head、title、styles、content、footer和scripts,分别用来划分不同的代码。其中,head块表示<head>标签的内容,title表示<title>标签的内容,content块表示页面主题内容,footer表示页脚部分,styles块和scripts块分别用来包含CSS文件和javaScript文件引用链接或页内的CSS和javaScript代码。

这里的块名称可以随意指定,而且并不是必须的。你可以按照需要设置块,如果只需要让字模板添加主体内容,那么仅定义一个content块就足够了。

以content块为例,模板继承示意图如下:

为了避免块的混乱,块的结束标签可以指明块名,同时要确保前后名称一致。

如:

{% block body %}

{% endblock body %}

编写子模板

因为基模板中定义了HTML的基本结构,而且包含了页脚等固定信息,在子模板中我们不再需要定义这些内容,只需要对特定的块进行修改。这时我们可以修改前面创建的电影清单模板watchlist.html和主页模板index.html,将这些子模板的通用部分合并到基模板中,并在子模板中定义块来组织内容,以便在渲染时将块中的内容插入到基模板的对应位置。

以index.html为例,修改后的index.html子模板如下:

{% extends 'base.html' %}
{% from 'macros.html' import qux %}

{% 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 %}

我们使用extends标签声明扩展基模板,它告诉模板引擎当前模板继承base.html

extends必须是字模板的第一个标签。

我们在基模板中定义了四个块,在子模板中,我们可以对父模板中的块进行两种操作:

1 覆盖内容

当在字模板里创建同名的块时,会使用子块的内容覆盖父块的内容。比如在字模板index.html中定义了title块,内容为Home,这会把块中的内容填充到基模板里的title块的位置,最终渲染为<title>Home</title>,content块的效果同理。

2 追加内容

如果要向基模板中的块追加内容,需要使用jinja2提供的super()函数进行声明,这会向父块添加内容。比如,下面例子中向基模板中的styles块追加了一行<style>样式定义:

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

当字模板被渲染时,它会继承基模板的所有内容,然后根据我们定义的块进行覆盖或追加操作,渲染子模板index.html的结果:

相当于把base.html的内容先拷贝过来,然后根据子模板中的内容进行定型,比如覆盖了什么块

<!DOCTYPE html>
<html lang="en">
<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>
原文地址:https://www.cnblogs.com/xiaxiaoxu/p/10434386.html