Python的Flask框架标配模板引擎Jinja2的使用教程


Posted in Python onJuly 12, 2016

Jinja2需要Python2.4以上的版本。
安装
按照Jinja有多种方式,你可以根据需要选择不同的按照方式。
使用easy_install 或pip:

#sudo easy_install Jinja2 
#sudo pip install Jinja2
这两个工具可以自动从网站上下载Jinja,并安装到python目录的site-packages目录中。
从tar包安装:
# 下载Jinja的安装包 
# 解压缩 
# sudo python setup.py install

基本API用法
用Jinja创建模板最简单的方式是通过 Template. 但在实际应用中并不推荐此用法: 

<pre> 
 >>> from Jinja2 import Template 
 >>> template = Template('Hello {{ name }}!') 
 >>> template.render(name='World') 
 u'Hello World!' 
</pre>

这个例子使用字符串作为模板内容创建了一个Template实例,然后用"name='World'"作为参数调用"render方法,将内容中 的'name'替换为"World",最终返回渲染过的字符串--"u'Hello World!'"。
有两种分隔符。{% raw %}{% ... %}{% endraw %} 和 {% raw %}{{ ... }}{% endraw %}。第一个用于执行类似 for 循环或者赋值的声明,后者是用于输出表达的结果到模板中。

如何组织模板
那么模板如何融入到我们的应用程序?如果你一直关注 Flask 的话,你可能注意到了 Flask 是十分灵活,它并没有对其内容进行一些特殊的限制。模板也不例外。你可能也注意到了通常有一个推荐的地方来放置东西(比如,模板)。对于模板而言,那个地方就是在包的目录里。

myapp/
  __init__.py
  models.py
  views/
  templates/
  static/
run.py
requirements.txt
templates/
  layout.html
  index.html
  about.html
  profile/
    layout.html
    index.html
  photos.html
  admin/
    layout.html
    index.html
    analytics.html

templates 目录的结构是与我们路由结构平行的。对于路由 myapp.com/admin/analytics 的模板就是 templates/admin/analytics.html。在目录里面还有一些额外的模板,它们不会直接地被渲染。layout.html 文件是为了让其它的模板继承。

继承
很像蝙蝠侠的背景故事一样,一个组织优秀的模板目录很大程度上依靠继承。父模板 通常定义一个通用的结构,所有 子模板 都能很好的继承它。在我们的例子中,layout.html 就是一个父模板而其它 .html 文件就是子模板。
你通常有一个顶层的 layout.html,它定义了你的应用程序的通用布局以及你的网站的每一部分。如果你看看上面的目录的话,你会看到一个顶层的 myapp/templates/layout.html,同样还有 myapp/templates/profile/layout.html 和 myapp/templates/admin/layout.html。最后两个文件继承和修改第一个文件。

{# _myapp/templates/layout.html_ #}
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>{% raw %}{% block title %}{% endblock %}{% endraw %}</title>
  </head>
  <body>
  {% block body %}
    <h1>This heading is defined in the parent.</h1>
  {% endblock %}
  </body>
</html>

在子模板中,我们可以扩展父模板并且定义这些块的内容。

{# _myapp/templates/index.html_ #}
{% extends "layout.html" %}
{% block title %}Hello world!{% endblock %}
{% block body %}
  {{ super() }}
  <h2>This heading is defined in the child.</h2>
{% endblock %}

super() 函数让我们渲染父级块的内容。

创建宏
我们可以在我们模板中坚持 DRY(不要重复自己)的原则,通过抽象出重复出现的代码片段到 宏。如果我们正工作在为我们应用程序导航的 HTML 上,我们需要给一个 “活跃的”链接一个 class(class=”active”)。没有宏的话,我们要编写一大段 if ... else 语句,这些语句检查每一个链接找到正处于活跃的一个。
宏提供了一种模块化代码的方式;它们像函数一样工作。让我们看看如何使用宏标记一个活跃的链接。

{# myapp/templates/layout.html #}
{% from "macros.html" import nav_link with context %}
<!DOCTYPE html>
<html lang="en">
  <head>
  {% block head %}
    <title>My application</title>
  {% endblock %}
  </head>
  <body>
    <ul class="nav-list">
      {{ nav_link('home', 'Home') }}
      {{ nav_link('about', 'About') }}
      {{ nav_link('contact', 'Get in touch') }}
    </ul>
  {% block body %}
  {% endblock %}
  </body>
</html>

在这个模板中我们现在要做的就是调用一个未定义的宏 - nav_link -接着向其传递两个参数:目标端点(例如,目标视图的函数名)以及我们要显示的文本。
你可能会注意到在导入语句中我们指定了 with context。Jinja 的 context 是由传递到 render_template() 函数的参数以及来自我们的 Python 代码的 Jinja 环境上下文组成。对于模板来说,这些变量在模板被渲染的时候是可用的。
一些变量是明显地由我们传入,例如,render_template("index.html", color="red"),但是还有一些变量和函数是由 Flask 自动地包含在上下文中,例如,request, g 和 session。当我们说 {% raw %}{% from ... import ... with context %}{% endraw %} 的时候,就是告诉 Jinja 这些变量对宏也可用。
现在是时候定义在我们模板中使用的 nav_link 宏。

{# myapp/templates/macros.html #}
{% macro nav_link(endpoint, text) %}
{% if request.endpoint.endswith(endpoint) %}
  <li class="active"><a href="{{ url_for(endpoint) }}">{{text}}</a></li>
{% else %}
  <li><a href="{{ url_for(endpoint) }}">{{text}}</a></li>
{% endif %}
{% endmacro %}

现在我们已经在 myapp/templates/macros.html 中定义了宏。在这个宏中我们使用了 Flask 的 request 对象 — 默认情况下在 Jinja 上下文中是可用的 — 用来检查传入到 nav_link 中的路由的端点是否是当前请求。如果是,我们正在当前页面上,接着我们标记它为活跃的。
从 x 导入 y 语句采用了 x 的相对路径。如果我们的模板是 myapp/templates/user/blog.html,我们可以在使用 from "../macros.html" 导入 nav_link。

自定义过滤器
Jinja 过滤器是一个函数,它能够在 {% raw %}{{ ... }}{% endraw %} 中用于处理一个表达式的结果。在表达式结果输出到模板之前它就被调用。

<h2>{{ article.title|title }}</h2>

在这段代码中,title 过滤器接收 article.title 作为参数并且返回一个过滤后的标题,接着过滤后的标题将会输出到模板中。这就像 UNIX 的“管道化”一个程序到另一个程序的输出。
有很多像 title 一样的内置过滤器。请参阅 Jinja 文档中的 完整列表。
我们可以在我们的 Jinja 模板中定义自己的过滤器供使用。举例来说,我们将会实现一个简单 caps 过滤器用来大写一个字符串中所有的字母。
Jinja 已经有一个 upper 过滤器来做这样的事情,并且还有一个 capitalize 过滤器,它能用来大写第一个字母,小写其余的字母。这些也能处理 unicode 转换,但是我们会继续我们的示例,让大家目前能够知道如何自定义过滤器。
我们要在 myapp/util/filters.py 中定义我们的过滤器。这里给出一个 util 包,它里面有各种各样的模块。

# myapp/util/filters.py
from .. import app
@app.template_filter()
def caps(text):
  """Convert a string to all caps."""
  return text.uppercase()

在这段代码中我们使用 @app.template_filter() 装饰器注册我们的函数成一个 Jinja 过滤器。默认的过滤器名称就是函数的名称,但是你可以传入一个参数到装饰器中来改变它。

@app.template_filter('make_caps')
def caps(text):
  """Convert a string to all caps."""
  return text.uppercase()

现在我们可以在模板中调用 make_caps 而不是 {% raw %}caps:{{ "hello world!"|make_caps }}{% endraw %}。
为了要让我们的过滤器在模板中可用的话,我们只需要在我们的顶层 \\_init.py\\_ 的中导入它。

# myapp/__init__.py
# Make sure app has been initialized first to prevent circular imports.
from .util import filters
Python 相关文章推荐
Tornado Web服务器多进程启动的2个方法
Aug 04 Python
python求众数问题实例
Sep 26 Python
Python中的面向对象编程详解(下)
Apr 13 Python
Python使用xlrd模块操作Excel数据导入的方法
May 26 Python
python基于BeautifulSoup实现抓取网页指定内容的方法
Jul 09 Python
各种Python库安装包下载地址与安装过程详细介绍(Windows版)
Nov 02 Python
Python实现Windows和Linux之间互相传输文件(文件夹)的方法
May 08 Python
对python pandas读取剪贴板内容的方法详解
Jan 24 Python
pandas DataFrame 警告(SettingWithCopyWarning)的解决
Jul 23 Python
python中68个内置函数的总结与介绍
Feb 24 Python
解决django的template中如果无法引用MEDIA_URL问题
Apr 07 Python
Python如何批量生成和调用变量
Nov 21 Python
深度定制Python的Flask框架开发环境的一些技巧总结
Jul 12 #Python
Python的面向对象编程方式学习笔记
Jul 12 #Python
Python使用cookielib模块操作cookie的实例教程
Jul 12 #Python
Python网络编程中urllib2模块的用法总结
Jul 12 #Python
Python中内置的日志模块logging用法详解
Jul 12 #Python
Swift 3.0在集合类数据结构上的一些新变化总结
Jul 11 #Python
浅析Python的web.py框架中url的设定方法
Jul 11 #Python
You might like
php5新改动之短标记启用方法
2008/09/11 PHP
深入PHP数据加密详解
2013/06/18 PHP
php socket客户端及服务器端应用实例
2014/07/04 PHP
PHP模板引擎Smarty之配置文件在模板变量中的使用方法示例
2016/04/11 PHP
深入理解JavaScript系列(7) S.O.L.I.D五大原则之开闭原则OCP
2012/01/15 Javascript
40个新鲜出炉的jQuery 插件和免费教程[上]
2012/07/24 Javascript
js控制表单奇偶行样式的简单方法
2013/07/31 Javascript
使用jquery选择器如何获取父级元素、同级元素、子元素
2014/05/14 Javascript
node.js中的fs.utimesSync方法使用说明
2014/12/15 Javascript
js使用心得分享
2015/01/13 Javascript
完美实现bootstrap分页查询
2015/12/09 Javascript
解析预加载显示图片艺术
2016/12/05 Javascript
深入理解JavaScript中的尾调用(Tail Call)
2017/02/07 Javascript
仿淘宝JSsearch搜索下拉深度用法
2018/01/15 Javascript
vue中mint-ui的使用方法
2018/04/04 Javascript
深入浅析vue中cross-env的使用
2019/09/12 Javascript
[05:39]2014DOTA2国际邀请赛 DK晋级胜者组专访战队国士无双
2014/07/14 DOTA
教你如何将 Sublime 3 打造成 Python/Django IDE开发利器
2014/07/04 Python
python中对list去重的多种方法
2014/09/18 Python
python 时间戳与格式化时间的转化实现代码
2016/03/23 Python
深入解析Python的Tornado框架中内置的模板引擎
2016/07/11 Python
Python 面试中 8 个必考问题
2018/11/16 Python
ERLANG和PYTHON互通实现过程详解
2019/07/05 Python
python实现淘宝购物系统
2019/10/25 Python
python实现身份证实名认证的方法实例
2019/11/08 Python
django rest framework serializers序列化实例
2020/05/13 Python
浅谈keras中loss与val_loss的关系
2020/06/22 Python
用60行代码实现Python自动抢微信红包
2021/02/04 Python
大学生简历中个人的自我评价
2013/10/06 职场文书
水污染治理专业毕业生推荐信
2013/11/14 职场文书
工商干部先进事迹
2014/05/14 职场文书
质量提升方案
2014/06/16 职场文书
安全承诺书
2015/01/19 职场文书
学习新党章心得体会2016
2016/01/15 职场文书
创业计划书之花店
2019/09/20 职场文书
Spring-cloud Config Server的3种配置方式
2021/09/25 Java/Android