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实现的udp协议Server和Client代码实例
Jun 04 Python
利用Python学习RabbitMQ消息队列
Nov 30 Python
Python 爬虫的工具列表大全
Jan 31 Python
Python使用Mechanize模块编写爬虫的要点解析
Mar 31 Python
python实现串口自动触发工作的示例
Jul 02 Python
远程部署工具Fabric详解(支持Python3)
Jul 04 Python
Django密码系统实现过程详解
Jul 19 Python
Python FFT合成波形的实例
Dec 04 Python
Python3 A*寻路算法实现方式
Dec 24 Python
Python tcp传输代码实例解析
Mar 18 Python
详解python算法常用技巧与内置库
Oct 17 Python
浅谈Python数学建模之固定费用问题
Jun 23 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的面试题集,附我的答案和分析(一)
2006/11/19 PHP
利用phpexcel把excel导入数据库和数据库导出excel实现
2014/01/09 PHP
jquery中常用的SET和GET
2009/01/13 Javascript
jQuery插件zoom实现图片全屏放大弹出层特效
2015/04/15 Javascript
jQuery实现ctrl+enter(回车)提交表单
2015/10/19 Javascript
详解vue.js组件化开发实践
2016/12/14 Javascript
vue子组件使用自定义事件向父组件传递数据
2017/05/27 Javascript
vue给input file绑定函数获取当前上传的对象完美实现方法
2017/12/15 Javascript
JS实现统计字符串中字符出现个数及最大个数功能示例
2018/06/04 Javascript
在vue中使用express-mock搭建mock服务的方法
2018/11/07 Javascript
JS+php后台实现文件上传功能详解
2019/03/02 Javascript
详解vue-cli3开发Chrome插件实践
2019/05/29 Javascript
Vue中的transition封装组件的实现方法
2019/08/13 Javascript
node.js中事件触发器events的使用方法实例分析
2019/11/23 Javascript
手动实现把python项目发布为exe可执行程序过程分享
2014/10/23 Python
使用Python的内建模块collections的教程
2015/04/28 Python
合并百度影音的离线数据( with python 2.3)
2015/08/04 Python
在Python中使用正则表达式的方法
2015/08/13 Python
Django验证码的生成与使用示例
2017/05/20 Python
Python判断两个对象相等的原理
2017/12/12 Python
python kmeans聚类简单介绍和实现代码
2018/02/23 Python
Pandas 数据处理,数据清洗详解
2018/07/10 Python
Python 面试中 8 个必考问题
2018/11/16 Python
在Tensorflow中实现leakyRelu操作详解(高效)
2020/06/30 Python
python写文件时覆盖原来的实例方法
2020/07/22 Python
白宫黑市官网:White House Black Market
2016/11/17 全球购物
ebookers英国:隶属全球最大的在线旅游公司Expedia
2017/12/28 全球购物
KOHLER科勒美国官网:国际著名卫浴橱柜领先品牌
2020/06/27 全球购物
如何将字串String转换成整数int
2015/02/21 面试题
中学教师培训制度
2014/01/31 职场文书
红领巾广播站广播稿
2014/02/01 职场文书
干部鉴定材料
2014/05/18 职场文书
大学生村官考核材料
2014/05/23 职场文书
numpy数据类型dtype转换实现
2021/04/24 Python
MySQL GRANT用户授权的实现
2021/06/18 MySQL
python 单机五子棋对战游戏
2022/04/28 Python