赵走x博客
网站访问量:151928
首页
书籍
软件
工具
古诗词
搜索
登录
Flask 实战:41、电子邮件进阶实践
Flask 实战:40、使用事务邮件服务SendGird
Flask 实战:39、使用Flask-Mail发送电子邮件
Flask 实战:38、数据库进阶实践
Flask 实战:37、更新数据库表
Flask 实战:36、定义关系
Flask 实战:35、在视图函数里操作数据库
Flask 实战:34、数据库操作:CRUD
Flask 实战:33、使用Flask-SQLAlchemy管理数据库
Flask 实战:32、ORM魔法
Flask 实战:31、数据库的分类
Flask 实战:30、单个页面多个表单
Flask 实战:29、单个表单多个提交按钮
Flask 实战:28、使用Flask-CKEditor集成富文本编辑器
Flask 实战:27、多文件上传
Flask 实战:26、文件上传
Flask 实战:25、自定义验证器
Flask 实战:24、使用宏渲染表单
Flask 实战:23、设置错误消息语言
Flask 实战:22、处理表单数据
Flask 实战:21、使用Flask-WTF处理表单
Flask 实战:20、HTML表单
Flask 实战:19、模板进阶实践
Flask 实战:18、模板结构组织
Flask 实战:17、模板辅助工具
Flask 实战:16、模板基本用法
Flask 实战:15、HTTP进阶实践
Flask 实战:14、Flask上下文
Flask 实战:13、HTTP响应
Flask 实战:12、HTTP请求
Flask 实战:11、请求响应循环
Flask 实战:10、Flask与MVC架构
Flask 实战:9、模板与静态文件
Flask 实战:8、Flask命令
Flask 实战:7、URL与端点
Flask 实战:6、项目配置
Flask 实战:5、Flask扩展
Flask 实战:4、Python Shell
Flask 实战:3、启动开发服务器
Flask 实战:2、Hello,Flask!
Flask 实战:1、初识Flask
Flask 实战:18、模板结构组织
资源编号:75856
Python Web
Flask Web开发实战:入门、进阶与原理解析
热度:86
除了使用函数、过滤器等工具控制模板的输出外,Jinja2还提供了一些工具来在宏观上组织模板内容。借助这些技术,我们可以更好地实践DRY(Don't Repeat Yourself)原则。
除了使用函数、过滤器等工具控制模板的输出外,Jinja2还提供了一些工具来在宏观上组织模板内容。借助这些技术,我们可以更好地实践DRY(Don't Repeat Yourself)原则。 # 1、局部模板 在Web程序中,我们通常会为每一类页面编写一个独立的模板。比如主页模板、用户资料页模板、设置页模板等。这些模板可以直接在视图函数中渲染并作为HTML响应主体。除了这类模板,我们还会用到另一类非独立模板,这类模板通常被称为局部模板或次模板,因为它们仅包含部分代码,所以我们不会在视图函数中直接渲染它,而是插入到其他独立模板中。 > 提示 当程序中的某个视图用来处理AJAX请求时,返回的数据不需要包含完整的HTML结构,这时就可以返回渲染后的局部模板。 当多个独立模板中都会使用同一块HTML代码时,我们可以把这部分代码抽离出来,存储到局部模板中。这样一方面可以避免重复,另一方面也可以方便统一管理。比如,多个页面中都要在页面顶部显示一个提示条,这个横幅可以定义在局部模板_banner.html中。 我们使用include标签来插入一个局部模板,这会把局部模板的全部内容插在使用include标签的位置。比如,在其他模板中,我们可以在任意位置使用下面的代码插入_banner.html的内容: ``` {% include '_banner.html' %} ``` 为了和普通模板区分开,局部模板的命名通常以一个下划线开始。 # 2、宏 宏(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中,出于性能的考虑,并且为了让这一切保持显式,默认情况下包含(include)一个局部模板会传递当前上下文到局部模板中,但导入(import)却不会。具体来说,当我们使用render_template()函数渲染一个foo.html模板时,这个foo.html的模板上下文中包含下列对象: * Flask使用内置的模板上下文处理函数提供的g、session、config、request。 * 扩展使用内置的模板上下文处理函数提供的变量。 * 自定义模板上下文处理器传入的变量。 * 使用render_template()函数传入的变量。 * Jinja2和Flask内置及自定义全局对象。 * Jinja2内置及自定义过滤器。 * Jinja2内置及自定义测试器。 使用include标签插入的局部模板(比如_banner.html)同样可以使用上述上下文中的变量和函数。而导入另一个并非被直接渲染的模板(比如macros.html)时,这个模板仅包含下列这些对象: * ·Jinja2和Flask内置的全局函数和自定义全局函数。 * ·Jinja2内置及自定义过滤器。 * ·Jinja2内置及自定义测试器。 因此,如果我们想在导入的宏中使用第一个列表中的2、3、4项,就需要在导入时显式地使用with context声明传入当前模板的上下文: ``` {% from "macros.html" import foo with context %} ``` >注意 虽然Flask使用内置的模板上下文处理函数传入session、g、request和config,但它同时也使用app.jinja_env.globals字典将这几个变量设置为全局变量,所以我们仍然可以在不显示声明传入上下文的情况下,直接在导入的宏中使用它们。 关于宏的编写,更多的细节请访问[http://jinja.pocoo.org/docs/latest/templates/#macros](http://jinja.pocoo.org/docs/latest/templates/#macros) 查看。 # 3、模板继承 Jinja2的模板继承允许你定义一个基模板,把网页上的导航栏、页脚等通用内容放在基模板中,而每一个继承基模板的子模板在被渲染时都会自动包含这些部分。使用这种方式可以避免在多个模板中编写重复的代码。 ### 1.编写基模板 基模板存储了程序页面的固定部分,通常被命名为base.html或layout.html。示例程序中的基模板base.html中包含了一个基本的HTML结构,我们还添加了一个简单的导航条和页脚: ``` {% block head %}
{% block title %}Template - HelloFlask{% endblock %}
{% block styles %}{% endblock %} {% endblock %}
Home
{% block content %}{% endblock %}
{% block scripts %}{% endblock %} ``` 当子模板继承基模板后,子模板会自动包含基模板的内容和结构。为了能够让子模板方便地覆盖或插入内容到基模板中,我们需要在基模板中定义块(block),在子模板中可以通过定义同名的块来执行继承操作。 块的开始和结束分别使用block和endblock标签声明,而且块之间可以嵌套。在这个基模板中,我们创建了六个块:head、title、styles、content、footer和scripts,分别用来划分不同的代码。其中,head块表示标签的内容,title表示
标签的内容,content块表示页面主体内容,footer表示页脚部分,styles块和scripts块,则分别用来包含CSS文件和JavaScript文件引用链接或页内的CSS和JavaScript代码。 >提示 这里的块名称可以随意指定,而且并不是必须的。你可以按照需要设置块,如果你只需要让子模板添加主体内容,那么仅定义一个content块就足够了。 以content块为例,模板继承示意图如图3-2所示。  图3-2 模板继承示意图 为了避免块的混乱,块的结束标签可以指明块名,同时要确保前后名称一致。比如: ``` {% block body %} ... {% endblock body %} ``` ### 2.编写子模板 因为基模板中定义了HTML的基本结构,而且包含了页脚等固定信息,在子模板中我们不再需要定义这些内容,只需要对特定的块进行修改。这时我们可以修改前面创建的电影清单模板watchlist.html和主页模板index.html,将这些子模板的通用部分合并到基模板中,并在子模板中定义块来组织内容,以便在渲染时将块中的内容插入到基模板的对应位置。以index.html为例,修改后的模板代码: ``` {% extends 'base.html' %} {% from 'macros.html' import qux %} {% block content %} {% set name='baz' %}
Template
Watchlist
Filter: {{ foo|musical }}
Global: {{ bar() }}
Test: {% if name is baz %}I am baz.{% endif %}
Macro: {{ qux(amount=5) }}
{% endblock %} ``` 我们使用extends标签声明扩展基模板,它告诉模板引擎当前模板派生自base.html。 >注意 extends必须是子模板的第一个标签。 我们在基模板中定义了四个块,在子模板中,我们可以对父模板中的块执行两种操作: #### (1)覆盖内容 当在子模板里创建同名的块时,会使用子块的内容覆盖父块的内容。比如我们在子模板index.html中定义了title块,内容为Home,这会把块中的内容填充到基模板里的title块的位置,最终渲染为
Home
,content块的效果同理。 #### (2)追加内容 如果想要向基模板中的块追加内容,需要使用Jinja2提供的super()函数进行声明,这会向父块添加内容。比如,下面的示例向基模板中的styles块追加了一行 {% endblock %} ``` 当子模板被渲染时,它会继承基模板的所有内容,然后根据我们定义的块进行覆盖或追加操作,渲染子模板index.html的结果如下所示: ```
Template - HelloFlask
Home
Template
Watchlist
Filter: I am foo. ♫
Global: I am bar.
Test: I am baz.
Macro: We are quxs.
```