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类方法__init__和__del__构造、析构过程分析
Mar 06 Python
从Python的源码来解析Python下的freeblock
May 11 Python
详细解读Python中解析XML数据的方法
Oct 15 Python
Python按行读取文件的实现方法【小文件和大文件读取】
Sep 19 Python
python非递归全排列实现方法
Apr 10 Python
基于python内置函数与匿名函数详解
Jan 09 Python
Python爬虫抓取技术的一些经验
Jul 12 Python
Python字符编码转码之GBK,UTF8互转
Feb 09 Python
python中前缀运算符 *和 **的用法示例详解
May 28 Python
keras 两种训练模型方式详解fit和fit_generator(节省内存)
Jul 03 Python
Python下使用Trackbar实现绘图板
Oct 27 Python
pytorch MSELoss计算平均的实现方法
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
PHP中输出转义JavaScript代码的实现代码
2011/04/22 PHP
jquery下onpropertychange事件的绑定方法
2010/08/01 Javascript
js getBoundingClientRect() 来获取页面元素的位置
2010/11/25 Javascript
javascript-简单的日历实现及Date对象语法介绍(附图)
2013/05/30 Javascript
用innerhtml提高页面打开速度的方法
2013/08/02 Javascript
异步动态加载js与css文件的js代码
2013/09/15 Javascript
Jquery 类网页微信二维码图块滚动效果具体实现
2013/10/14 Javascript
jQuery响应鼠标事件并隐藏与显示input默认值
2014/08/24 Javascript
简介JavaScript中用于处理正切的Math.tan()方法
2015/06/15 Javascript
JavaScript代码性能优化总结篇
2016/05/15 Javascript
jquery判断页面网址是否有效的两种方法
2016/12/11 Javascript
js+html5实现侧滑页面效果
2017/07/15 Javascript
9102了,你还不会移动端真机调试吗
2019/03/25 Javascript
在vue项目中使用codemirror插件实现代码编辑器功能
2019/08/27 Javascript
vue实现学生信息管理系统
2020/05/30 Javascript
Python的Django框架下管理站点的基本方法
2015/07/17 Python
Python中Iterator迭代器的使用杂谈
2016/06/20 Python
python中获得当前目录和上级目录的实现方法
2017/10/12 Python
Django中reverse反转并且传递参数的方法
2019/08/06 Python
pytorch自定义初始化权重的方法
2019/08/17 Python
Python生成个性签名图片获取GUI过程解析
2019/12/16 Python
python爬虫开发之使用python爬虫库requests,urllib与今日头条搜索功能爬取搜索内容实例
2020/03/10 Python
pyqt5 QlistView列表显示的实现示例
2020/03/24 Python
Pytorch框架实现mnist手写库识别(与tensorflow对比)
2020/07/20 Python
Python getsizeof()和getsize()区分详解
2020/11/20 Python
html5视频播放_动力节点Java学院整理
2017/07/13 HTML / CSS
使用placeholder属性设置input文本框的提示信息
2020/02/19 HTML / CSS
Julep官网:美容产品和指甲油
2017/02/25 全球购物
荷兰时尚精品店:Labels Fashion
2020/03/22 全球购物
美食节目策划方案
2014/05/31 职场文书
离婚协议书范文2014
2014/10/16 职场文书
一年级数学上册复习计划
2015/01/17 职场文书
2015初中团委工作总结
2015/07/28 职场文书
小学体育组工作总结
2015/08/13 职场文书
导游词之韩国济州岛
2019/10/28 职场文书
详解Python为什么不用设计模式
2021/06/24 Python