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 相关文章推荐
Python heapq使用详解及实例代码
Jan 25 Python
Python对List中的元素排序的方法
Apr 01 Python
python 获取文件下所有文件或目录os.walk()的实例
Apr 23 Python
Python字典创建 遍历 添加等实用基础操作技巧
Sep 13 Python
python循环定时中断执行某一段程序的实例
Jun 29 Python
python 实现保存最新的三份文件,其余的都删掉
Dec 22 Python
Pycharm pyuic5实现将ui文件转为py文件,让UI界面成功显示
Apr 08 Python
Python特殊属性property原理及使用方法解析
Oct 09 Python
Python self用法详解
Nov 28 Python
利用python+request通过接口实现人员通行记录上传功能
Jan 13 Python
python openpyxl模块的使用详解
Feb 25 Python
将Python代码打包成.exe可执行文件的完整步骤
May 12 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
经典的星际争霸,满是回忆的BGM
2020/04/09 星际争霸
thinkphp框架类库扩展操作示例
2019/11/26 PHP
12种不宜使用的Javascript语法整理
2013/11/04 Javascript
JavaScript初学者建议:不要去管浏览器兼容
2014/02/04 Javascript
JavaScript检查弹出窗口是否被阻拦的方法技巧
2015/03/13 Javascript
异步JavaScript编程中的Promise使用方法
2015/07/28 Javascript
深入学习Bootstrap表单
2016/12/13 Javascript
详解Javascript几种跨域方式总结
2017/02/27 Javascript
Angular多选、全选、批量选择操作实例代码
2017/03/10 Javascript
在Vue项目中引入腾讯验证码服务的教程
2018/04/03 Javascript
Angular ElementRef简介及其使用
2018/10/01 Javascript
JS复杂判断的更优雅写法代码详解
2018/11/07 Javascript
vue动画效果实现方法示例
2019/03/18 Javascript
layer关闭弹出窗口触发表单提交问题的处理方法
2019/09/25 Javascript
[51:15]2014 DOTA2国际邀请赛中国区预选赛 Orenda VS LGD-GAMING
2014/05/22 DOTA
Python3 入门教程 简单但比较不错
2009/11/29 Python
Centos5.x下升级python到python2.7版本教程
2015/02/14 Python
Python简单检测文本类型的2种方法【基于文件头及cchardet库】
2016/09/18 Python
python 环境变量和import模块导入方法(详解)
2017/07/11 Python
用python的requests第三方模块抓取王者荣耀所有英雄的皮肤实例
2017/12/14 Python
Python爬虫将爬取的图片写入world文档的方法
2018/11/07 Python
pandas去除重复列的实现方法
2019/01/29 Python
python使用turtle绘制国际象棋棋盘
2019/05/23 Python
解决Python计算矩阵乘向量,矩阵乘实数的一些小错误
2019/08/26 Python
python里的单引号和双引号的有什么作用
2020/06/17 Python
关于HTML5的安全问题开发人员需要牢记的
2012/06/21 HTML / CSS
下面关于"联合"的题目的输出是什么
2013/08/06 面试题
C#基础面试题
2016/10/17 面试题
关于礼仪的演讲稿
2014/01/04 职场文书
人力资源主管职责范本
2014/03/05 职场文书
小学五年级学生评语
2014/04/22 职场文书
运动会拉拉队口号
2014/06/09 职场文书
介绍信范文大全
2015/05/07 职场文书
golang判断key是否在map中的代码
2021/04/24 Golang
详解Python常用的魔法方法
2021/06/03 Python
mysql5.5中文乱码问题解决的有用方法
2022/05/30 MySQL