mako模板笔记

来源:互联网 发布:柏柏尔人 知乎 编辑:程序博客网 时间:2024/05/16 18:35
 转自:http://hi.baidu.com/1878/blog/item/81fb8fd409f92809a08bb713.html

    ${next.body()}
表示下一级继承页面用

在pylons中设置为utf-8编码

在pylons工程config/environment.py文件最后,添加

tmpl_options['mako.default_filters'] = ['decode.utf8']

修改模板路径:

config/environment.py 中的

# Create the Mako TemplateLookup, with the default autoescaping
config['pylons.app_globals'].mako_lookup= TemplateLookup(
    directories=paths['templates'],
    ...
)

使用 <%doc> 做多行注释

<%text>更进一步,注释可以包含 模板中的变量,

<%text>
    This is some Mako syntax which will not be executed: ${variable}
    Neither will this <%doc>be treated as a comment</%doc>
</%text>

控制结构:

用%开头,结束如果是IF % endif

可以使用<% %>写代码段,在代码段的变量可以在模板中的其它部分 以 ${} 调用

得到当前URL

${h.url_for()}

<%include>

类似于其他模板语言的一个标签,%include 接受一个文件名称作为参数,调用被引用文件的输出结果。

<%include file="header.html"/>    hello world<%include file="footer.html"/>

<%def>

%def 标签用于定义包含一系列内容的一个 Python 函数,此函数在当前模板的其他某个地方被调用到:

<%def name="myfunc(x)">    this is myfunc, x is ${x}</%def>${myfunc(7)}

%def 标签比 Python 的 def 要强大一些,因为 Mako 的编译器为 %def 提供了很多额外服务,比如可以导出 defs 为模板“方法”,自动传播当前的 context (原文:automatic propigation of the current Context),缓冲/过滤/缓存 标志位,以及带有内容的 def 调用,这使得 defs 的包可以被以参数的形式,提供给其他的 def 调用(不像听起来那么困难)。

<%inherit>

允许模板可以在继承链中安排其自身的位置。这是其他很多模板语言都有的一个熟悉的概念。

<%inherit file="base.html"/>

当使用 %inherit 标签时,首先,控制权被转交给继承树最顶层的父模板,由它来决定如何配合继承自它的子模板来处理其中的调用区域(calling areas)的内容。Mako 在这方面提供了很多灵活性,包括动态继承(dynamic inheritance), 内容包装(content wrapping), 以及多态的方法调用(polymorphic method calls). 详见Inheritance

<%call>

call 标签用于调用 <%defs %> 标签,可传递额外的内嵌内容。

Context

Context 是模板被第一次执行前创建的一个核心对象,它负责和模板外部做所有的交互。它由两个主要的组件组成,1. 输出缓冲区,这是一个类似文件的对象,比如 Python 的 StringIO;2. 变量字典,其中的所有变量均可在模板中自由引用,该字典是由传递给 template.rener() 方法的参数,以及一些由 Mako 运行时环境提供的内建变量组成。

% for key in context.keys():
The key is <tt>${key}</tt>, the value is ${str(context.get(key))}. <br />
% endfor

缓冲区

缓冲区存储在 Context 中,通过 context.write() 方法可以写缓冲区。通常你不需要关注此方法,因为模板中的文本和 ${} 形式的表达式,都会自动将输出提交到该方法。只有在下列几个应用场景下你才可能需要用到它:1. 处理各种过滤/缓冲(详见Filtering and Buffering),2. 用编程的方式将内容发送到输出流,比如在一个 <% %> 块中。

<%    context.write("some programmatic text")%>

实际的缓冲区可能不是原来发送给 Context 对象的那个,因为在各种过滤/缓存的场景下,可能会 "push" 一个新的缓冲区到 context 内部的缓冲区栈上。正因为此,只要我们记住始终调用 context.write() 方法,就可以确保内容被发送到顶层的缓冲区。

上下文变量

当模板被编译为 python 模块时,其页面内容被包含在 render_body 这个函数中。其他顶层的 defs, 会在其各自独立的函数中定义,函数名被附加了一个前缀 "render_"(比如 render_mydef)。在这些函数中,所有在本地没有定义的变量(比如通过赋值或模块导入的方式定义的),都会从 Context 对象的变量字典中提取。

  • 如果引用当前上下文中不存在的变量会怎么样? - 你取得的值将是一个特殊的值 UNDEFINED. 它是 mako.runtime.Undefined 类的一个全局变量。UNDEFINED 对象会在你尝试调用 str() 时抛出错误。这会在尝试在表达式中使用它的时候发生。

  • 为什么不直接返回 None 呢? UNDEFINED 更明确,可以和人为传递到 Context 中的 None 加以区分,以及和没有提供值的变量区分开来。

  • 为什么对它调用 str() 时会引发异常,而不是返回空字符串呢? - Mako 一直在努力遵循 python 的哲学 “明确胜于隐晦”(explicit is better than implicit). 具体来说,模板作者应该处理值丢失的情况,而不是默默的任由其出错。因为 UNDEFINED 和 python 的 True 或 False 一样,是个单件(Singleton) 对象,你可以用 is 运算符来检查它:

    % if someval is UNDEFINED:    someval is: no value% else:    someval is: ${someval}% endif

另一个值得注意的方面是,Context 的变量字典是不可变的。当然,因为是纯 python 的方式,你可以修改 context 的变量字典中的变量,但这恐怕不会如你想像。原因是,Mako 会在很多情况下会创建 Context 对象的副本,并将这些副本传递给模板中的各种元素,以及执行过程中可能用到的子模板。所以,修改本地 Context 中的值,不一定会在模板的其他部分生效。Mako 创建 Context 副本的一个例子是,在模板体中进行对顶层 def 的调用(context 被用于传递局部变量到 def 的范围中;因为在模板体内,他们以内联函数的形式出现,Mako 会尝试让他们用这种方式工作)。另一个例子是在继承链中(在链中的每个模板都有其不同的 parent 和 next,而这两个变量就保存在各自唯一的 Context 对象中)。

  • 那么,我们如何设定相对于一个模板请求过程的全局变量呢? - 只要在模板初次运行时给 Context 提供一个字典即可,然后所有的地方就都可以向该字典中 get/set 变量了。比如叫做 attributes:

运行模板:

output = template.render(attributes={})

在模板中,直接引用该字典:

<%    attributes['foo'] = 'bar'%>'foo' attribute is: ${attributes['foo']}
  • 为什么"attributes" 不是 Context 的内建特性呢? - 这也是 Mako 替你的应用程序尽量少做决定的一个体现。也许你不想在模板里用这种技术读写和共享数据,又或者你想用不同的变量名或数据结构来传递。再一次的,Mako 宁愿用户明确一点。

上下文方法和访问器(Context Methods and Accessors)

Context 的主要成员包括:

  • context[key] / context.get(key, default=None) - 类似字典方式的访问器。通常你在模板中使用的变量,如果在局部没有定义,则会去上下文中获取。当你要使用一个在别处已经定义的(比如传递给 %def 调用的局部参数)变量时,可以用字典访问语法或 get 方法。如果没有提供 key, 则和字典类似,会引发 KeyError.

  • keys() - 上下文中已定义的所有名称。

  • kwargs - 这会返回一个上下文变量字典的副本。当你想把当前上下文中的变量传递到函数的关键字参数时,这样做很有用。例如:

    ${next.body(**context.kwargs)}
  • write(text) - 向当前输出流中写一些文本。

  • lookup - 返回当前执行中用于所有文件查找请求的 TemplateLookup 对象(尽管每个独立的 Template 实例可以有其不同的 TemplateLookup 实例,但只有最初调用到的那个 Template 的 TemplateLookup 会被使用)。

All the built-in names

现在来看看 Mako 定义了的所有名称。下面的大多数名称是 Namespace 的实例(下一节中有详细介绍:Namespaces),并且,下面除了 context 和 UNDEFINED 之外的大多数变量名称都定义在 Context 中。

  • local - 当前模板的名称空间, described inBuilt-in Namespaces
  • self - 继承链顶层模板的名称空间 (如果有的话,没有则和 local 一样), mostly described inInheritance
  • parent - 继承链中父模板的名称空间(或者未定义); seeInheritance
  • next - 继承链中下一个模板的名称空间(或未定义); seeInheritance
  • caller - 当使用 <%call> 标签定义一个“带内容的调用”时创建的一个“迷你”名称空间。 described inCalling a def with embedded content and/or other defs
  • capture - 一个函数,用于调用指定的 def 并捕获其输出内容,返回为字符串。 Usage is described inBuffering
  • UNDEFINED - 一个全局的单件对象,用于在 Context 中找不到的变量的返回值。是mako.runtime.Undefined 类的实例,调用其 __str__() 方法会引发异常。
  • pageargs - 在没有在 <%page> 标签中定义任何关键字参数的模板中有效,是一个字典。所有传递给模板 body() 函数(当通过名称空间使用时)的关键字参数,都会被收集到这个字典中,其他则被定义为页面参数。(如果已经预先声明)。[原文:All keyword arguments sent to thebody() function of a template (when used via namespaces) go here by default unless otherwise defined as a page argument.] If this makes no sense, it shouldn't; read the sectionThe "body()" method.
  • 表达式转义(escaping)

    Mako 包含了一系列内建的转义机制,包括 HTML, URI 和 XML 转义,以及 "trim" 函数。转义的动作可以通过 | 运算符附加到表达式后面:

    ${"this is some text" | u}

    上例中对表达式进行了 URL 转义,其结果是:this+is+some+text. 其中 u 代表 URL 转义,与之类似的,h 代表 HTML 转义,x 代表 XML 转义,而 trim 则是通常的 trim 函数。

    可以在 Filtering and Buffering 中获取更多关于过滤器函数的内容,包括如何创建你自己的过滤器。

    A literal''is a specialtype derived from Python's built-in ``unicode type. When the escape() function finds aliteral it doesn't escape it.

    literal 是一个由PYTHON内建类型UNICODE 派生出来的一个特殊类型,escape() 函数发现literal 时,将不转义

    c.greeting = literal('<b>Welcome</b>') 在模板中调用c.greeting 时,Welcome 显示时是加重的


原创粉丝点击