跳转到主要内容

Grok页面模板支持Chameleon

项目描述

megrok.chameleon

megrok.chameleon 允许在Grok中使用Chameleon模板。

目前提供了对Chameleon Genshi模板和Chameleon Zope页面模板的支持。

有关Grok和Chameleon模板的更多信息,请参阅

需求

  • Chameleon模板(Chameleon)。

  • Chameleon genshi模板(chameleon.genshi)。

  • Grok v1.0a1或更高版本,或five.grok 1.0或更高版本。

安装

要使用Chameleon页面模板与Grok,您只需要安装megrok.chameleon作为egg并包含其ZCML。最好将megrok.chameleon作为您的应用程序的依赖项,通过将其添加到setup.cfg中的install_requires列表中来实现。如果您使用grokproject创建应用程序,则setup.py位于项目根目录。它看起来可能像这样

install_requires=['setuptools',
                  'megrok.chameleon',
                  # Add extra requirements here
                  ],

然后,在您的configure.zcml中包含megrok.chameleon。如果您使用grokproject创建应用程序,它位于src/<projectname>/configure.zcml。在grok的包含行之后,但在当前包的grokking之前添加包含行。它看起来可能像这样

<include package="grok" />
<include package="megrok.chameleon" />
<grok:grok package="." />

如果您在configure.zcml中使用autoInclude,则不需要进行此后续步骤。

然后再次运行bin/buildout。现在您应该会看到buildout显示类似于以下内容的信息

Getting distribution for 'megrok.chameleon'.
Got megrok.chameleon 0.5.

就这些了。现在您可以在Grok应用程序中使用Chameleon页面模板了。

使用

megrok.chameleon支持Grok标准,将模板放在模板目录中,例如app_templates,因此您可以通过在模板目录中放置Chameleon Genshi模板或Chameleon Zope页面模板来使用Chameleon页面模板,就像使用常规ZPT模板一样。尽管Chameleon模板本身没有模板文件扩展名的标准,但Grok需要将扩展名与类型关联起来,以便知道每个模板的类型。megrok.chameleon定义了以下扩展名

  • .cptChameleon页面模板)用于Chameleon页面模板

  • .cgChameleon genshi模板)用于由Chameleon驱动的Genshi模板

  • .cgtChameleon genshi文本模板)用于由Chameleon驱动的Genshi文本模板

您还可以内联使用Chameleon页面模板。这种语法的例子是

from megrok.chameleon.components import ChameleonPageTemplate
index = ChameleonPageTemplate('<html>the html code</html>')

或者如果您使用文件

from megrok.genshi.components import ChameleonPageTemplateFile
index = ChameleonPageTemplateFile(filename='thefilename.html')

详细描述

支持使用Chameleon驱动的模板的Grok。

使用megrok.chameleon,您可以使用由Chameleon解析和渲染的模板。目前支持Zope页面模板和Genshi模板。

Chameleon Zope页面模板

Chameleon为Zope页面模板提供支持,可以使用带有.cpt(=Chameleon Page Template)文件扩展名的.cpt文件从grok编写模板。

Chameleon页面模板与标准Zope页面模板在几个方面有所不同,最值得注意的是

  • 默认情况下,表达式通过Python-mode进行解析。这意味着,您必须使用tal:content="view.value"而不是tal:content="view/value"。现在,以python:开头的TAL表达式的每个出现都可以通过跳过此标记来缩短。

  • 此外,还支持类似于Genshi的变量替换。例如,您可以写出${myvar}而不是tal:content="myvar"

除此之外,大多数常规Zope页面模板的规则也适用于Chameleon页面模板。

有关更多信息,请参阅Chameleon页面。

先决条件

在我们能够看到模板的实际效果之前,我们关注正确的注册并设置一些使用的变量

>>> import os
>>> testdir = os.path.join(os.path.dirname(__file__), 'tests')
>>> cpt_fixture = os.path.join(testdir, 'cpt_fixture')
>>> template_dir = os.path.join(cpt_fixture, 'app_templates')

我们注册一切。在我们能够理解我们的测试用例之前,我们必须理解megrok.chameleon包。这样,新的模板类型就会通过框架注册

>>> import grokcore.view
>>> grokcore.view.testing.grok('megrok.chameleon')
>>> grokcore.view.testing.grok('megrok.chameleon.tests.cpt_fixture')

我们创建一个庞然大物,它应该提供大量由Chameleon页面模板驱动的视图,并将其放入数据库中以设置位置信息

>>> from megrok.chameleon.tests.cpt_fixture.app import Mammoth
>>> manfred = Mammoth()
>>> getRootFolder()['manfred'] = manfred

此外,我们为获取关于Manfred的不同视图做好准备

>>> from zope.publisher.browser import TestRequest
>>> from zope.component import getMultiAdapter
>>> request = TestRequest()

简单模板

我们准备了一个简单的洞穴壁画视图。模板看起来像这样

>>> cavepainting_cpt = os.path.join(template_dir, 'cavepainting.cpt')
>>> print open(cavepainting_cpt, 'rb').read()
<html>
  <body>
    A cave painting.
  </body>
</html>

渲染后的视图看起来像这样

>>> view = getMultiAdapter((manfred, request),
...                         name='cavepainting')
>>> print view()
<html>
  <body>
    A cave painting.
  </body>
</html>

替换变量

模板可以访问变量,如viewcontext及其方法和属性。food视图正是这样做的。模板看起来像这样

>>> food_cpt = os.path.join(template_dir, 'food.cpt')
>>> print open(food_cpt, 'rb').read()
<html>
<body>
<span tal:define="foo 'a FOO'">
${view.me_do()}
<span tal:replace="structure view.me_do()" />
CSS-URL: ${static['test.css']()}
My context is: ${view.url(context)}
${foo}
<span tal:replace="foo" />
</span>
</body>
</html>

渲染后的视图看起来像这样

>>> view = getMultiAdapter((manfred, request), name='food')
>>> print view()
<html>
<body>
<span>
&lt;ME GROK EAT MAMMOTH!&gt;
<ME GROK EAT MAMMOTH!>
CSS-URL: http://127.0.0.1/@@/megrok.chameleon.tests.cpt_fixture/test.css
My context is: http://127.0.0.1/manfred
a FOO
a FOO
</span>
</body>
</html>

如我们所见,Genshi-like替换和TAL-like替换之间有一个区别:虽然这两个表达式

${view.me_do()}

<span tal:replace="view.me_do()" />

实际上渲染了相同的字符串<ME GROK EAT MAMMOTH!>,但前者直接而简洁地完成,而后者对字符串执行额外的HTML编码。因此,这两个表达式的输出不同。对于前者表达式是

<ME GROK EAT MAMMOTH!>

而对于后者是

&lt;ME GROK EAT MAMMOTH!&gt;

支持变量

每个模板至少提供以下变量

  • 模板

    模板实例

  • 视图

    关联的视图

  • 上下文

    视图的上下文

  • 请求

    当前请求

  • 静态

    应用程序的静态目录

正如我们所见,当我们查看我们测试用例中的vars.cpt并对其进行渲染时

>>> cpt_file = os.path.join(template_dir, 'vars.cpt')
>>> print open(cpt_file, 'rb').read()
<html>
<body>
This template knows about the following vars:
<BLANKLINE>
  template (the template instance):
   ${template}
<BLANKLINE>
  view (the associated view):
   ${view}
<BLANKLINE>
  context (the context of the view):
   ${context}
<BLANKLINE>
  request (the current request):
   ${request}
<BLANKLINE>
  static (the static dir of the application):
   ${static}
</body>
</html>

>>> view = getMultiAdapter((manfred, request), name='vars')
>>> print view()
<html>
<body>
This template knows about the following vars:
<BLANKLINE>
  template (the template instance):
   &lt;vars template in ...vars.cpt&gt;
<BLANKLINE>
  view (the associated view):
   &lt;megrok.chameleon.tests.cpt_fixture.app.Vars object at 0x...&gt;
<BLANKLINE>
  context (the context of the view):
   &lt;megrok.chameleon.tests.cpt_fixture.app.Mammoth object at 0x...&gt;
<BLANKLINE>
  request (the current request):
   CONTENT_LENGTH:  0
GATEWAY_INTERFACE:  TestFooInterface/1.0
HTTP_HOST:  127.0.0.1
SERVER_URL: http://127.0.0.1
<BLANKLINE>
  static (the static dir of the application):
   &lt;grokcore.view.components.DirectoryResource object at 0x...&gt;
</body>
</html>

内联模板

我们还可以定义内联模板。在我们的app.py中,我们定义了一个内联模板,如下所示

from megrok.chameleon import components

...

class Inline(grokcore.view.View):
  sometext = 'Some Text'

inline = components.ChameleonPageTemplate(
    "<html><body>ME GROK HAS INLINES! ${view.sometext}</body></html>")

如果我们渲染这个视图,我们会得到

>>> view = getMultiAdapter((manfred, request), name='inline')
>>> print view()
<html><body>ME GROK HAS INLINES! Some Text</body></html>

TAL表达式

megrok.chameleon 0.5版本开始,我们部署了完整的Chameleon包。

模板中支持的TAL/TALES表达式取决于Chameleon的安装版本,同时我们支持一些额外的与Zope相关的TALES表达式。

所有支持的表达式和语句的列表可以在chameleon.zpt文档中找到。由megrok.chameleon提供的额外TALES表达式包括

  • 存在

    告诉一个名称是否存在于模板的命名空间中。

  • 将尾随表达式评估为布尔值并对其进行反转。

  • 路径

    将尾随表达式作为路径处理,而不是作为Python表达式。

  • 提供者

    支持视图小部件提供者。

在我们的app.py中,我们定义了一个特殊的视图来显示一些特殊表达式。这也包括一个视图小部件

import grok
from megrok.chameleon import components

class Mammoth(grok.Application, grok.Container):
    pass

...

class Expressions(grok.View):
    pass

class MainArea(grok.ViewletManager):
    grok.name('main')

class MainContent(grok.Viewlet):
    grok.view(Expressions)
    grok.viewletmanager(MainArea)
    def render(self):
        return 'Hello from viewlet'

现在我们可以在我们的fixture的expressions.cpt模板中使用TALES表达式not:path:exists:provider:

>>> cpt_file = os.path.join(template_dir, 'expressions.cpt')
>>> print open(cpt_file, 'rb').read()
<html>
<body>
  <div tal:define="food 'Yummy Dinoburger'"
       tal:omit-tag="">
    <!-- We support `exists` -->
    <div tal:condition="exists: food">
      ${food}
    </div>
<BLANKLINE>
    <!-- We support `not` -->
    <div tal:content="not: food" />
    <div tal:content="not('food')" />
    <div tal:content="not: 1 in [2,3]" />
    <div tal:content="not: not: food" />
<BLANKLINE>
    <!-- We support `path` -->
    <div tal:content="path: food/upper" />
<BLANKLINE>
    <!-- We support `provider` -->
    <tal:main content="structure provider:main" />
<BLANKLINE>
  </div>
</body>
</html>

>>> view = getMultiAdapter((manfred, request), name='expressions')
>>> print view()
<html>
<body>
<BLANKLINE>
    <!-- We support `exists` -->
    <div>
      Yummy Dinoburger
    </div>
<BLANKLINE>
    <!-- We support `not` -->
    <div>False</div>
    <div>False</div>
    <div>True</div>
    <div>True</div>
<BLANKLINE>
    <!-- We support `path` -->
    <div>YUMMY DINOBURGER</div>
<BLANKLINE>
    <!-- We support `provider` -->
    Hello from viewlet
<BLANKLINE>
<BLANKLINE>
</body>
</html>

使用megrok.chameleon,我们还可以使用宏,尽管它与常规的Zope页面模板略有不同。

我们可以这样定义宏:

>>> cpt_file = os.path.join(template_dir, 'macromaster.cpt')
>>> print open(cpt_file, 'rb').read()
<p xmlns:metal="http://xml.zope.org/namespaces/metal"
   metal:define-macro="hello">
  Hello from <b metal:define-slot="name">macro master</b>
</p>

定义的宏hello可以在另一个Chameleon模板中使用,通过设置METAL属性use-macro

要引用本地宏,即在同一模板中定义的宏,可以使用如下方式:

<div metal:use-macro="template.macros['<macro-name>']">
  Replaced by macro
</div>

其中<macro-name>必须是已存在的宏名称。

要引用外部模板中的宏,必须使用path:表达式,如下所示:

<div metal:use-macro="path:
  context/@@<viewname>/template/macros/<macro-name>">
   Replaced by external macro
</div>

其中<viewname>指代在context上存在的视图,而<macro-name>再次指代在指定模板中存在的宏。

注意,这与您在标准Zope页面模板中引用宏的方式不同。简短表示法view/macros/<macro-name>仅适用于常规Zope页面模板。

以下模板同时使用了这两种方法:

>>> cpt_file = os.path.join(template_dir, 'macrouser.cpt')
>>> print open(cpt_file, 'rb').read()
<html xmlns:metal="http://xml.zope.org/namespaces/metal">
<body>
  <p metal:define-macro="hello">
    Hi there from macro user!
  </p>
  <div metal:use-macro="template.macros['hello']">
    Fill this
  </div>
<BLANKLINE>
  <div metal:use-macro="path: context/@@macromaster/template/macros/hello">
    <b metal:fill-slot="name">user slot</b>
    Fill this too
  </div>
</body>
</html>

渲染时,主模板中定义的槽位也被宏用户内容填充。

>>> cpt_file = os.path.join(template_dir, 'macrouser.cpt')
>>> view = getMultiAdapter((manfred, request), name='macrouser')
>>> print view()
<html>
<body>
  <p>
    Hi there from macro user!
  </p>
  <p>
    Hi there from macro user!
  </p>
<BLANKLINE>
<BLANKLINE>
  <p>
  Hello from <b>user slot</b>
<BLANKLINE>
</p>
</body>
</html>

清理

>>> del getRootFolder()['manfred']

与常规Zope页面模板的区别

  • 宏的引用方式不同。请参阅上面的相关部分。

  • 默认情况下,表达式通过Python-mode进行解析。这意味着,您必须使用tal:content="view.value"而不是tal:content="view/value"。现在,以python:开头的TAL表达式的每个出现都可以通过跳过此标记来缩短。

Chameleon Genshi模板

Chameleon提供了对Genshi模板的支持,可以使用具有.cg文件扩展名的grok编写模板。

Genshi文本模板可以使用.cgt文件扩展名。

注意,chameleon genshi模板可能不涵盖原生genshi解析器提供的全部功能。如果您想使用原生genshi支持,请使用megrok.genshi

有关更多信息,请参阅chameleon.genshi页面。

先决条件

在我们能够看到模板的实际效果之前,我们关注正确的注册并设置一些使用的变量

>>> import os
>>> testdir = os.path.join(os.path.dirname(__file__), 'tests')
>>> genshi_fixture = os.path.join(testdir, 'genshi_fixture')
>>> template_dir = os.path.join(genshi_fixture, 'app_templates')

我们注册一切。在我们能够理解我们的测试用例之前,我们必须理解megrok.chameleon包。这样,新的模板类型就会通过框架注册

>>> grokcore.view.testing.grok('megrok.chameleon')
>>> grokcore.view.testing.grok('megrok.chameleon.tests.genshi_fixture')

我们创建了一个巨大的mammoth,它应该为我们提供大量的Genshi驱动视图,并将其放入数据库中设置位置信息。

>>> from megrok.chameleon.tests.genshi_fixture.app import Mammoth
>>> manfred = Mammoth()
>>> getRootFolder()['manfred'] = manfred

此外,我们为获取关于Manfred的不同视图做好准备

>>> from zope.publisher.browser import TestRequest
>>> from zope.component import getMultiAdapter
>>> request = TestRequest()

简单模板

我们准备了一个简单的洞穴壁画视图。模板看起来像这样

>>> cavepainting_cg = os.path.join(template_dir, 'cavepainting.cg')
>>> print open(cavepainting_cg, 'rb').read()
<html>
  <body>
    A cave painting.
  </body>
</html>

渲染后的视图看起来像这样

>>> view = getMultiAdapter((manfred, request),
...                         name='cavepainting')
>>> print view()
<html>
  <body>
    A cave painting.
  </body>
</html>

替换变量

模板可以访问变量,如viewcontext及其方法和属性。food视图正是这样做的。模板看起来像这样

>>> food_cg = os.path.join(template_dir, 'food.cg')
>>> print open(food_cg, 'rb').read()
<html>
<body>
${view.me_do()}
CSS-URL: ${static['test.css']()}
My context is: ${view.url(context)}
</body>
</html>

渲染后的视图看起来像这样

>>> view = getMultiAdapter((manfred, request), name='food')
>>> print view()
<html>
<body>
ME GROK EAT MAMMOTH!
CSS-URL: http://127.0.0.1/@@/megrok.chameleon.tests.genshi_fixture/test.css
My context is: http://127.0.0.1/manfred
</body>
</html>

包含其他模板

有了genshi支持,我们还可以包含其他模板。gatherer视图看起来像这样:

>>> gatherer_cg = os.path.join(template_dir, 'gatherer.cg')
>>> print open(gatherer_cg, 'rb').read()
<html xmlns:xi="http://www.w3.org/2001/XInclude">
<body>
ME GROK GATHER BERRIES!
<xi:include href="berries.cg"/>
</body>
</html>

显然,这里包含了一个名为berries.cg的模板。它看起来像这样:

>>> berries_cg = os.path.join(template_dir, 'berries.cg')
>>> print open(berries_cg, 'rb').read()
<strong>Lovely blueberries!</strong>

当我们渲染前一个模板时,我们得到:

>>> view = getMultiAdapter((manfred, request), name='gatherer')
>>> print view()
<html>
<body>
ME GROK GATHER BERRIES!
<strong>Lovely blueberries!</strong>
</body>
</html>

文本模板

也支持genshi文本模板。我们有一个看起来是这样的模板:

>>> hunter_cgt = os.path.join(template_dir, 'hunter.cgt')
>>> print open(hunter_cgt, 'rb').read()
ME GROK HUNT ${view.game}!

注意,此模板具有.cgt (= c cameleon g genshi t text template)文件扩展名。

如果我们渲染它,所有表达式都被替换。

>>> view = getMultiAdapter((manfred, request), name='hunter')
>>> print view()
ME GROK HUNT MAMMOTH!!

变更日志

0.5.2 (2010-07-19)

  • 移除对chameleon.genshi的依赖,因为它现在已包含在Chameleon中。

0.5.1 (2010-05-20)

  • 使ITranslatorExpressions的注册条件化:如果同时安装了z3c.pt,则不注册我们自己的。这应该可以解决使用megrok.chameleon与其他需要z3c.pt的包(如z3c.form和grok-ecosphere的依赖包)时出现的DuplicationError。

  • 为测试移除zope.testing、zope.app.testing和z3c.testsetup。

0.5 (2010-03-03)

  • 添加了测试以展示使用megrok.chameleon宏的用法。

  • 通过复制相关部分并本地注册,移除了对z3c.pt的依赖。

    删除了对exists('varname')表达式的支持。仍然可以使用常规的TALES表达式exists: varname/path

  • 改为使用Chameleon而不是chameleon.*包。

0.4 (2010-02-23)

  • megrok声明为命名空间包。

  • 在ftesting.zcml中修复了包含顺序。

  • 将纯测试需求移入自己的setup-section,以减少常规(非测试)模式下的依赖。

0.3 (2010-02-14)

  • 添加了许可文件。

0.2 (2009-09-18)

  • 从模板提供宏访问。

  • 不要再依赖grok,而只使用grokcore.view。

  • 在页面模板中增加了对path()exists()的支持。这是从z3c.pt引入的。

  • 修复ZCML包含。

0.1 (2009-02-22)

  • 初始发布

项目详情


下载文件

下载适合您平台的文件。如果您不确定该选择哪个,请了解更多关于安装包的信息。

源代码分布

megrok.chameleon-0.5.2.tar.gz (20.7 kB 查看散列)

上传时间 源代码

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面