跳转到主要内容

为Grok提供的Chameleon页面模板支持

项目描述

grokcore.chameleon

grokcore.chameleon 使得在 Grok 中使用 Chameleon 页面模板成为可能。有关 Grok 和 Chameleon 页面模板的更多信息,请参见

安装

请注意,grok 的未来版本将自身依赖于 grokcore.chameleon 并对其进行配置。换句话说,基于 chameleon 的模板将从该版本开始默认可用!

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

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

请注意,如果您的项目 buildout.cfg 中使用 allow-picked-versions = false 指令,您必须将几个软件包的版本号指定添加到 [versions] 部分。

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

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

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

然后再次运行 bin/buildout。现在您应该看到 buildout 输出如下(版本号可能不同)

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

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

使用方法

grokcore.chameleon 支持 Grok 标准的模板放置在模板目录中,例如 app_templates,因此您可以通过将 Chameleon 页面模板放置在模板目录中,像使用常规 ZPT 模板一样,来使用 Chameleon 页面模板。

尽管 chameleon 模板本身没有模板文件扩展名的标准,但 Grok 需要在文件扩展名和模板语言实现之间建立关联,以便知道使用哪个实现。

grokcore.chameleon 声明使用扩展名 *.cptChameleon page template)用于 Chameleon 页面模板。

您还可以内联使用 Chameleon 页面模板。其语法如下

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

或如果您使用文件

from grokcore.chameleon.components import ChameleonPageTemplateFile
index = ChameleonPageTemplateFile(filename='thefilename.html')

详细描述

Grok 支持 Chameleon 驱动的模板。

使用 grokcore.chameleon,您可以使用由 Chameleon 解析和渲染的模板,并使用 Zope 页面模板模板语言。

Chameleon Zope 页面模板

Chameleon支持Zope页面模板,可以使用.grok编写模板,文件扩展名为.cpt(=Chameleon页面模板)。

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

  • 默认情况下,表达式以Python模式解析。这意味着,您必须使用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')

我们注册一切。在我们可以grok我们的 fixture之前,我们必须grok grokcore.chameleon 包。这样,新的模板类型就被注册到框架中

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

我们创建一个巨兽,它应该提供许多由Chameleon页面模板驱动的视图,并将其放入数据库以设置位置信息

>>> from grokcore.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')
>>> with open(cavepainting_cpt, 'r') as f:
...     print(f.read())
<html>
  <body>
    A cave painting.
  </body>
</html>

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

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

变量替换

模板可以访问如view、context、static以及其方法和属性。food视图正是如此。模板看起来像这样

>>> food_cpt = os.path.join(template_dir, 'food.cpt')
>>> with open(food_cpt, 'r') as f:
...     print(f.read())
<html>
<body>
<span tal:define="foo 'a FOO'">
${view.me_do()}
<span tal:replace="structure view.me_do()" />
CSS-URL: ${path: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: dummy:/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!>

,后者为

&lt;ME GROK EAT MAMMOTH!&gt;

支持的变量

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

  • template

    模板实例

  • view

    关联视图

  • context

    视图上下文

  • request

    当前请求

正如我们所看到的,当我们查看我们的fixture中的vars.cpt

>>> cpt_file = os.path.join(template_dir, 'vars.cpt')
>>> with open(cpt_file, 'r') as f:
...     print(f.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}
</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;PageTemplateFile ...vars.cpt&gt;
<BLANKLINE>
  view (the associated view):
   &lt;grokcore.chameleon.tests.cpt_fixture.app.Vars object at 0x...&gt;
<BLANKLINE>
  context (the context of the view):
   &lt;grokcore.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
</body>
</html>

支持自定义模板命名空间名称

>>> view = getMultiAdapter((manfred, request), name='namespace')
>>> print(view())
<html>
<body>
This template knows about the following custom namespace name:
<BLANKLINE>
  myname:
   Henk
<BLANKLINE>
</body>
</html>

内联模板

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

from grokcore.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 表达式

grokcore.chameleon 0.5版本开始,我们部署了全功能的Chameleon包。

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

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

  • exists

    告诉模板命名空间中是否存在名称。

  • not

    将表达式评估为布尔值并取反。

  • path

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

  • provider

    支持视图提供者。

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

import grok
from grokcore.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')
>>> with open(cpt_file, 'r') as f:
...     print(f.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>

翻译

>>> # Monkeypatch zope.i18n.negotiate
>>> import zope.i18n
>>> import zope.i18n.config
>>> print(getMultiAdapter((manfred, request), name='menu')())
<html>
<body>
  <h1>Menu</h1>
  <ol>
    <li>Deepfried breaded veal cutlets</li>
  </ol>
</body>
</html>
>>> # What's for food today in Germany?
>>> # We need to monkey patch the language settings for this test.
>>> old_1, old_2 = zope.i18n.negotiate, zope.i18n.config.ALLOWED_LANGUAGES
>>> zope.i18n.negotiate = lambda context: 'de'
>>> zope.i18n.config.ALLOWED_LANGUAGES = ['de']
>>> print(getMultiAdapter((manfred, request), name='menu')())
<html>
<body>
  <h1>Menu</h1>
  <ol>
    <li>Schnitzel</li>
  </ol>
</body>
</html>
>>> # Restore the monkey patch.
>>> zope.i18n.negotiate, zope.i18n.config.ALLOWED_LANGUAGES = old_1, old_2

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

我们可以这样定义宏

>>> cpt_file = os.path.join(template_dir, 'macromaster.cpt')
>>> with open(cpt_file, 'r') as f:
...     print(f.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')
>>> with open(cpt_file, 'r') as f:
...     print(f.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模式解析。这意味着,您必须使用tal:content="view.value",而不是tal:content="view/value"。现在,所有以python:开始的TAL表达式现在可以通过跳过此标记来缩短。

变更记录

4.0 (2023-02-09)

  • 取消对 Python 2.7、3.4、3.5、3.6 的支持。

  • 添加对 Python 3.7、3.8、3.9、3.10、3.11 的支持。

3.0.1 (2018-01-12)

  • 重新排列测试,以便 Travis CI 可以获取所有功能测试。

3.0.0 (2018-01-11)

  • Python 3 兼容性。

1.0.4 (2014-07-29)

  • 使用 Chameleon 2.10 或更高版本改进翻译机制的性能。

1.0.3 (2012-10-12)

  • 修复使用 Chameleon 2.9 或更高版本时损坏的翻译。

1.0.2 (2012-05-07)

  • 由于没有使用 z3c.pt PageTemplateFile 基类,相对于模块查找模板文件的行为丢失了。这已被修复。

1.0.1 (2012-05-03)

  • 确保定义了最小版本要求。

1.0 (2012-05-01)

  • 在版本 1.0rc4 中丢失了 target_language 混淆。从 z3c.pt 复制。

1.0rc4 (2012-01-03)

  • 升级到最新的 Chameleon 2.7.1

  • 直接从 Chameleon 使用一些组件/表达式,而不是 z3c.pt

1.0rc3 (2011-07-14)

  • 将 megrok.chameleon 重命名为 grokcore.chameleon,使其成为 Grok 的官方部分。

早期版本

  • 早期版本的 grokcore.chameleon 以 megrok.chameleon 的名称出现。

项目详情


下载文件

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

源分布

grokcore.chameleon-4.0.tar.gz (25.1 kB 查看散列)

上传时间: 源代码

构建版本

grokcore.chameleon-4.0-py3-none-any.whl (24.4 kB 查看哈希值)

上传时间: Python 3

由以下提供支持