前言
来啦老铁!
今天咱们继续一起来学习Python模板引擎Jinja2的另外2个重要知识点:
-
宏;
-
模板继承;
代码已更新至仓库,自行取阅:
1. 宏;
简单的说,宏与代码中方法的封装、前端组件的概念类似,即我们对Jinja2模板中经常使用的页面元素(当然,也可以是复杂的页面片段)进行封装,这样可以方便代码复用,降低代码冗余。同时,支持有入参的宏。
还不够清楚?咱们来实践实践!宏的编写有2种方式:
-
一种是在模板中直接进行封装;
-
一种是将代码块封装到独立的宏文件中去;
(可以参考一下我们平时怎么封装方法、函数的)
1). 在模板中直接进行封装:
- 在模板文件夹中新增jinja2_maro_demo_1.html,织入如下模板代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% macro input(id, type='text', value='') %}
<input type="{{ type }}" id="{{ id }}" value="{{ value|e }}">
{% endmacro %}
Username:<p>{{ input('username',value=user_name) }}</p>
Password:<p>{{ input('password', type='password',value=pass_word) }}</p>
</body>
</html>
- 这个东西就是宏:
{% macro input(id, type='text', value='') %}
<input type="{{ type }}" id="{{ id }}" value="{{ value|e }}">
{% endmacro %}
这里将一个input框抽成一个宏,入参id,type(带有默认值text),value分别为input html元素的3种属性,这样我们可以根据传递给宏的参数,渲染出含有不同属性的input框,如普通input框,密码input框等。
- 而这个就是使用宏的示例:
(其中user_name和pass_word是模板的外部入参,由渲染逻辑传入)
Username:<p>{{ input('username',value=user_name) }}</p>
Password:<p>{{ input('password', type='password',value=pass_word) }}</p>
- 最后写一个渲染逻辑:
(我们给模板传一个user_name为dylanz、pass_word为123的参数)
def create_jinja2_macro_demo_1_html(self):
env = Environment(loader=PackageLoader('resources', 'templates'))
template_name = 'jinja2_macro_demo_1.html'
template = env.get_template(template_name)
html = template.render(user_name='dylanz', pass_word='123')
self.write_output_html(template_name, html)
- 执行渲染逻辑;
- 渲染完成后,浏览器打开output文件夹下新生成的jinja2_macro_demo_1.html文件
这样我们就完成了一个带入参的宏,被渲染出多个页面元素的示例啦!
不带入参的宏更简单,把参数去掉就好了,如:
{% macro input() %}
<input type="text" id="test" value="">
{% endmacro %}
2). 将代码块封装到独立的宏文件中去;
承接上面的例子,我们将宏写到独立的文件中去,然后在模板文件中引入,最后完成渲染。
- 新建宏文件;
在模板文件下新建宏文件夹macros文件夹,在文件夹新建宏文件,如:macro_demo.html,在文件中织入宏代码(就是将宏代码搬到macro_demo.html而已):
{% macro input(id, type='text', value='') %}
<input type="{{ type }}" id="{{ id }}" value="{{ value|e }}">
{% endmacro %}
- 新的模板文件;
新建模板文件jinja2_macro_demo_2.html,织入代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% from 'macros/macro_demo.html' import input %}
Username:<p>{{ input('username',value=user_name) }}</p>
Password:<p>{{ input('password', type='password',value=pass_word) }}</p>
</body>
</html>
这里关键的一行代码,将宏引入模板文件:
{% from 'macros/macro_demo.html' import input %}
- 配套的渲染逻辑:
def create_jinja2_macro_demo_2_html(self):
env = Environment(loader=PackageLoader('resources', 'templates'))
template_name = 'jinja2_macro_demo_2.html'
template = env.get_template(template_name)
html = template.render(user_name='dylanz', pass_word='123')
self.write_output_html(template_name, html)
- 执行渲染逻辑;
- 渲染完成后,浏览器打开output文件夹下新生成的jinja2_macro_demo_2.html文件:
效果跟直接在模板中声明宏、引用宏一样,说明将代码块封装到独立的宏文件中去,然后再在模板中引用的示例正确无误!
这里有几个注意点:
a. 宏文件必须在模板文件夹下或模板文件夹下任意文件夹,因此我们是在templates下新建的macros文件夹;
b. 引入宏的方式,不仅只有{% from 'macros/macro_demo.html' import input %} 这种方式,其实import语句的用法跟python中的import类似,可以直接import...as...,也可以from...import...或者from...import...as...;
c. 宏文件中也可以引用其它宏,使用include关键字代码,如:
{% include 'other_macro_1.html' %}
自己的宏代码
{% include 'other_macro_2.html' %}
2. 模板继承;
模板的继承同样提高了模板代码的重复利用性,我们在父模板中预留位置(称之为block),子模板继承后,再对预留的位置进行实现,这样既保留父模板的通用部分,又能对某些模板位置进行定制。
废话不多说,咱直接开整!
我们在templates文件夹下建立2个模板文件parent.html和child.html:
- parent.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>这被继承的父模板</div>
{% block content %}
<div>这里是预留位置</div>
{% endblock %}
</body>
</html>
其中,这个就是父模板中为字模板预留的位置,<div>这里是预留位置</div>是我们自己随便放的用于标记一下,真实场景中也可以放任意html:
{% block content %}
<div>这里是预留位置</div>
{% endblock %}
(注意:content为block名字,可任意取)
- child.html:
{% extends "parent.html" %}
{% block content %}
{{ super() }}
<p>
Hi,这是子模板定制的内容
</p>
{% endblock %}
- 渲染逻辑:
def create_child_html(self):
env = Environment(loader=PackageLoader('resources', 'templates'))
template_name = 'child.html'
template = env.get_template(template_name)
html = template.render()
self.write_output_html(template_name, html)
- 执行渲染逻辑:
展示前介绍几个注意点:
a. 子模板就不用再写完整的模板文件了;
子模板直接继承parent.html,然后往父模板预留的位置写入内容,如本例为:Hi,这是子模板定制的内容:
{% block content %}
{{ super() }}
<p>
Hi,这是子模板定制的内容
</p>
{% endblock %}
b. 当使用了{{ super() }},则父模板预留位置内的内容会保留,即<div>这里是预留位置</div>这个会保留:
继承示例1:有{{ super() }}c. 当未使用{{ super() }},则则父模板预留位置内的内容不保留,即<div>这里是预留位置</div>这个会去除:
继承示例2:无{{ super() }}d. 如果父模板中,想使用预留位置的内容,则可以像这样,在父模板中添加代码:
<div>
父模板中再次使用预留位置的内容:
{{self.content()}}
</div>
继承示例3:父模板使用预留位置的内容
至此,我们学习实践了Jinja2的2个重要概念,Jinja2学到这里基本就告一段落了,剩下的就交给时间,交给具体使用场景的考验了!
整个不会很难,建议跟着文章动手做,很容易就能理解。
当然笔者也是参考网上的一些文章,如有不足或错误,烦请指正,感谢!
如果本文对您有帮助,麻烦动动手指点点赞?
谢谢!
网友评论