边做边学Python Flask Web开发(5)-- 使用Jinjia2模板(中)

上一篇介绍了Jinjia2模板系统的基本用法,本篇将深入对Jinjia2进行探讨,对网页设计中经常会用到的一些高级特性进行介绍。

模板复用

复用是网页设计非常常用的特性,比如我们的页面头部的网站名称和页尾的版权标识通常都是一样的,我们的菜单有时候在每个页面也都是一样的。作为一名程序员,重复做同样的事情是完全不可接受的。在Jinjia2中,通常可以使用继承、包含和宏三种特性来完成模板的利用。

继承

这和类的继承没有什么分别,因此也就有了父模板和子模板的概念。例如,我们可以把包含HTML框架、页头、页尾的模板页做为父模板,其它的子模板只需要继承它,就自动拥有了头部和尾部。

下面是一个父模板的例子:

<html>
<head>     
{% block head %}     
<title>{% block title %}Base Title{% endblock %} - My Application</title>
{% endblock %} 
</head> 
<body>     
<h1>This Header is inherited from base.html</h1>
{% block body %}     {% endblock %} 
<hr/>
This footer is inherited from base.html
</body> 
</html>

现在我们在templates目录新建一个文件,写下一行代码,保存为child.html

{% extends "base.html" %}

在创建了Flask app的源代码中加上一个路由/child,完整的代码如下:

import json,pprint,sys
from flask import Flask,render_template
app = Flask(__name__) 

@app.route('/child')
def child1():
    return render_template("child.html")

if __name__ == '__main__':
    app.run(debug=True)

运行这个程序我们看到如下的结果:

这里写图片描述

注意红色标记的部分,这个页面的title仍然是Base Title,原因是我们在子模板中并没有对{% block title %}进行改写。将child.html扩充:

{% extends "base.html" %}
{% block title %} Child1 {% endblock %}
{% block body %}<h2> This is body of child1 </h2> {% endblock %}

再看看页面的标题已被替换,body部分也被充实了内容。

这里写图片描述

模板继承中,可以使用一个特殊的super函数,将父模板内容块中定义的内容附加到子模板中,这有点像Python类的super函数。

{% block title%}
    Child1 - 
    {{ super() }}
{% endblock %}

大家可以动手试一下这样写的话页面的标题会变成什么样子。

包含

可以使用include将一个独立的模板文件包含进来,这一点和PHP非常相似。我们继续修改child.html:

{% extends "base.html" %}
{% block title %} Child1 {% endblock %}
{% include 'menu.html' %}
{% block body %}<h2> This is body of child1 </h2> {% endblock %}

同时,新建一个名称是menu.html的模板文件,放置在同一目录下,内容如下:

<hr/>
<ul>
    <li>Menu Item 1</li>
    <li>Menu Item 2</li>
    <li>Menu Item 3</li>
<hr/>

现在的页面已经包含了一个菜单项。

这里写图片描述

最后我们介绍一下宏。宏的概念和大家了解的Office中的宏很类似,它通常用来做一些需要多次处理的简单工作。Jinjia2中定义和使用宏有点像定义和使用函数,下面继续我们的child.html,在里面添加上宏的定义和调用代码。

<!--这里先定义宏-->
{% macro render_comment(comment) %}     
    <li>MACRO:{{ comment }}</li> 
{% endmacro %}  
<!--定义结束-->
<!--调用宏-->
<ul>
{% for comment in comments %}         
    {{ render_comment(comment) }}     
{% endfor %} 
</ul>
<!--调用结束-->

我们还可以把宏代码放置在一个单独的文件中,下面我们新建一个文件macros.html,内容如下:

{% macro render_comment_from_file(comment) %}     
    <li>来自文件:{{ comment }}</li> 
{% endmacro %}  

从文件中载入宏代码用到了一个新的命令import,继续修改child.html,增加以下内容

<h4>这是由从文件导入的宏生成的</h4>
{% import 'macros.html' as macros %} 
<ul>     
{% for comment in comments %}         
    {{ macros.render_comment_from_file(comment) }}     
{% endfor %} 
</ul>

至此,完整的child.html文件如下:

{% extends "base.html" %}
{% block title %} Child1 {% endblock %}
{% include 'menu.html' %}
{% block body %}
<h2> This is body of child1 </h2> 
<!--这里先定义宏-->
{% macro render_comment(comment) %}     
    <li>MACRO:{{ comment }}</li> 
{% endmacro %}  
<!--定义结束-->
<!--调用宏-->
<ul>
{% for comment in comments %}         
    {{ render_comment(comment) }}     
{% endfor %} 
</ul>
<!--调用结束-->
<h4>这是由从文件导入的宏生成的</h4>
{% import 'macros.html' as macros %} 
<ul>     
{% for comment in comments %}         
    {{ macros.render_comment_from_file(comment) }}     
{% endfor %} 
</ul>
{% endblock %}

格式化

前几章中我们了解到,Jinjia2的工作模式是向模板发送数据再渲染成HTML页面。不过在很多情况下,发送到页面的数据并不是我们期望的格式,这时候就要用到它的格式化功能。

Jinjia2中的格式化操作最常见的是使用过滤器进行的。

字符串

我们用一个例子对字符串的格式化操作进行说明,将下面的代码保存为strings.html

<h1>Hello {{user}}</h1>
<hr />
<p>转为首字母大写: Hello, {{ user|capitalize }}</p>
<p>转为大写: Hello, {{ user|upper }}</p>
<p>转为小写: Hello, {{ user|lower }}</p>
<p>转为标题样式(每个主题词首字母大写): Hello, {{ user|title }}</p>
<p>去掉首尾空格(页面上无效果): Hello, {{ user|trim }}</p>
<p>默认的HTML过滤操作: {{ myhtmlstr }}</p>
<p>添加safe过滤器(有安全隐患,如果不能确认字符串是安全的请不要使用!): {{ myhtmlstr|safe }}</p>
<p>过滤掉HTML标记: {{ myhtmlstr|striptags }}</p>
<hr />

在创建了Flask app的源代码中加上一个路由/strings,完整的代码如下:

import json,pprint,sys
from flask import Flask,render_template
app = Flask(__name__) 

@app.route('/strings')
def strings():
    return render_template("strings.html",user="ivan wang",
                            myhtmlstr="<strong>this is <i>emphasized</i></strong>")

if __name__ == '__main__':
    app.run(debug=True)

该页面在浏览器中显示如下

这里写图片描述

数字

仍然使用一个例子来演示数字的格式化方法,将下面的代码保存为numerics.html:

<h2>和数字相关的过滤器</h2>
<p>四舍五入:{{n1|round}}</p>
<p>保留3位小数并四舍五入:{{n1|round(3)}}</p>
<p>保留1位小数下取整:{{n1|round(1,'floor')}}</p>
<p>保留1位小数上取整:{{n1|round(1,'ceil')}}</p>
<p>取整:{{n1|int}}</p>
<p>使用格式化字符串:{{"%.2f" % n1}}</p>
<p>使用string.format函数进行千分位显示:{{"{:,}".format(n2)}}</p>
<p>使用string.format函数对多个数字进行格式化:{{"Number1:{0:.2%}, Number2:{1:,}".format(n1,n2)}}</p>

在python代码中添加一个numerics路由:

@app.route('/numerics')
def numerics():
    return render_template("numerics.html",n1=3.14159,n2=29838721)

页面显示如下:

这里写图片描述

在Jinja2中使用格式化字符串和String.format为数字和字符的格式化输出带来了无限的可能,更多的信息请参考 https://docs.python.org/2/library/string.html#format-string-syntax

自定义

Jinja2内置了功能丰富的过滤器,可以参考[[http://jinja.pocoo.org/docs/dev/templates]]获取更多的信息。

如果所有内置的过滤器都不能满足要求,Jinja2还允许你创建自定义的过滤器。

添加一个userdefined路由,代码如下:

@app.template_filter('reverse')
def reverse_filter(s):
    return s[::-1]

@app.route('/userdefined')
def userdefined():
    return render_template("userdefined.html",s="abcdefg")

userdefined.html内容如下:

{{s|reverse}}

请大家自行尝试该模板的渲染结果。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值