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字符串连接方式汇总
Aug 21 Python
python自动化测试之从命令行运行测试用例with verbosity
Sep 28 Python
Python3处理文件中每个词的方法
May 22 Python
python 根据正则表达式提取指定的内容实例详解
Dec 04 Python
Python使用贪婪算法解决问题
Oct 22 Python
python高阶函数map()和reduce()实例解析
Mar 16 Python
利用scikitlearn画ROC曲线实例
Jul 02 Python
python实现PolynomialFeatures多项式的方法
Jan 06 Python
python实现web邮箱扫描的示例(附源码)
Mar 30 Python
pandas中DataFrame重置索引的几种方法
May 24 Python
Python爬虫基础之简单说一下scrapy的框架结构
Jun 26 Python
Python基于百度AI实现抓取表情包
Jun 27 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中的数组操作函数整理
2008/08/18 PHP
PHP邮件发送类PHPMailer用法实例详解
2014/09/22 PHP
Javascript 篱式条件判断
2008/08/22 Javascript
jquery 插件学习(六)
2012/08/06 Javascript
Python脚本后台运行的几种方式
2015/03/09 Javascript
jQuery满意度星级评价插件特效代码分享
2015/08/19 Javascript
原生js配合cookie制作保存路径的拖拽
2015/12/29 Javascript
超赞的jQuery图片滑块动画特效代码汇总
2016/01/25 Javascript
不定义JQuery插件 不要说会JQuery
2016/03/07 Javascript
在node中如何使用 ES6
2017/04/22 Javascript
NodeJS创建最简单的HTTP服务器
2017/05/15 NodeJs
Angular 4根据组件名称动态创建出组件的方法教程
2017/11/01 Javascript
pageGroup.js实现分页功能
2019/07/27 Javascript
Net微信网页开发 使用微信JS-SDK获取当前地理位置过程详解
2019/08/26 Javascript
[38:39]KG vs Mineski 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
python操作xml文件详细介绍
2014/06/09 Python
在Linux系统上通过uWSGI配置Nginx+Python环境的教程
2015/12/25 Python
python二分查找算法的递归实现方法
2016/05/12 Python
浅析PHP与Python进行数据交互
2018/05/15 Python
详解Python安装scrapy的正确姿势
2018/06/26 Python
pycharm编写spark程序,导入pyspark包的3中实现方法
2019/08/02 Python
基于Django OneToOneField和ForeignKey的区别详解
2020/03/30 Python
Python AutoCAD 系统设置的实现方法
2020/04/01 Python
python实现录音功能(可随时停止录音)
2020/10/26 Python
python 实现汉诺塔游戏
2020/11/28 Python
YSL圣罗兰美妆美国官网:Yves Saint Lauret US
2016/11/21 全球购物
eDreams葡萄牙:全球最大的在线旅行社之一
2019/04/15 全球购物
自我鉴定思想方面
2013/10/07 职场文书
酒吧创业计划书
2014/01/18 职场文书
商务考察邀请函范文
2014/01/21 职场文书
我的未来不是梦演讲稿
2014/09/02 职场文书
2014年转正工作总结
2014/11/08 职场文书
工厂清洁工岗位职责
2015/02/14 职场文书
创业计划书之熟食店
2019/10/16 职场文书
SpringCloud之@FeignClient()注解的使用方式
2021/09/25 Java/Android
mysql5.7的安装及Navicate长久免费使用的实现过程
2021/11/17 MySQL