QWeb 模板¶
QWeb 是 Odoo2 使用的主要模板引擎。它是一个 XML 模板引擎1,主要用于生成 HTML 片段和页面。
模板指令被指定为 XML 属性,前缀为 t-`, for instance ``t-if``(对于 条件句),元素和其他属性直接呈现。
为了避免元素渲染,还可以使用占位符元素“<t>”,它执行其指令但本身不生成任何输出:
<t t-if="condition">
<p>Test</p>
</t>
将导致:
<p>Test</p>
如果 condition 为 true,但是:
<div t-if="condition">
<p>Test</p>
</div>
将导致:
<div>
<p>Test</p>
</div>
数据输出¶
QWeb 的输出指令 out 将自动对其输入进行 HTML 转义,从而在显示用户提供的内容时限制 XSS 风险。
out 接受一个表达式,对其求值并将结果注入到文档中:
<p><t t-out="value"/></p>
使用值 value set to 42 渲染会产生:
<p>42</p>
请参阅 高级输出 了解更高级的主题(例如注入原始 HTML 等)。
条件句¶
QWeb 有一个条件指令 if,它计算作为属性值给出的表达式:
<div>
<t t-if="condition">
<p>ok</p>
</t>
</div>
如果条件为 true,则呈现该元素:
<div>
<p>ok</p>
</div>
但如果条件为假,则会从结果中删除:
<div>
</div>
条件渲染适用于指令的承载者,它不必是“<t>”:
<div>
<p t-if="condition">ok</p>
</div>
将给出与前面的示例相同的结果。
额外的条件分支指令 t-elif and t-else 也可用:
<div>
<p t-if="user.birthday == today()">Happy birthday!</p>
<p t-elif="user.login == 'root'">Welcome master!</p>
<p t-else="">Welcome!</p>
</div>
循环¶
QWeb 有一个迭代指令 foreach which take an expression returning the collection to iterate on, and a second parameter t-as 提供用于迭代的“当前项”的名称:
<t t-foreach="[1, 2, 3]" t-as="i">
<p><t t-out="i"/></p>
</t>
将呈现为:
<p>1</p>
<p>2</p>
<p>3</p>
与条件类似,``foreach``适用于具有指令属性的元素,并且
<p t-foreach="[1, 2, 3]" t-as="i">
<t t-out="i"/>
</p>
相当于前面的例子。
foreach 可以迭代数组(当前项将是当前值)或映射(当前项将是当前键)。仍然支持对整数进行迭代(相当于对介于 0 和提供的整数之间的数组进行迭代),但已弃用。
除了通过“t-as`, ``foreach`”传递的名称之外,还为各种数据点提供了一些其他变量:
警告
$as will be replaced by the name passed to t-as
- :samp:`{$as}_all`(已弃用)
被迭代的对象
注解
此变量仅在 JavaScript QWeb 上可用,在 Python 上不可用。
$as_value当前迭代值,与“
$as`for lists and integers, but for mappings it provides the value (where ``$as`”相同,提供了密钥)$as_index当前迭代索引(迭代的第一项索引为 0)
$as_size集合的大小(如果可用)
$as_first当前项是否是迭代的第一项(相当于
$as_index == 0)$as_last当前项是否是迭代的最后一项(相当于
$as_index + 1 == $as_size),需要迭代者的大小可用- :samp:`{$as}_parity`(已弃用)
要么
"even"or"odd",当前迭代轮次的奇偶校验- :samp:`{$as}_even`(已弃用)
一个布尔标志,指示当前迭代轮位于偶数索引上
- :samp:`{$as}_odd`(已弃用)
一个布尔标志,指示当前迭代轮位于奇数索引上
提供的这些额外变量以及创建到 foreach are only available in the scope of the foreach. If the variable exists outside the context of the foreach 中的所有新变量,该值在 foreach 末尾复制到全局上下文中。
<t t-set="existing_variable" t-value="False"/>
<!-- existing_variable now False -->
<p t-foreach="[1, 2, 3]" t-as="i">
<t t-set="existing_variable" t-value="True"/>
<t t-set="new_variable" t-value="True"/>
<!-- existing_variable and new_variable now True -->
</p>
<!-- existing_variable always True -->
<!-- new_variable undefined -->
属性¶
QWeb 可以即时计算属性并将计算结果设置在输出节点上。这是通过“t-att”(属性)指令完成的,该指令以 3 种不同的形式存在:
t-att-$name创建名为“
$name”的属性,评估属性值并将结果设置为属性的值:<div t-att-a="42"/>
将呈现为:
<div a="42"></div>
t-attf-$name与之前相同,但参数是 format string 而不仅仅是一个表达式,对于混合文字和非文字字符串(例如类)通常很有用:
<t t-foreach="[1, 2, 3]" t-as="item"> <li t-attf-class="row {{ (item_index % 2 === 0) ? 'even' : 'odd' }}"> <t t-out="item"/> </li> </t>
将呈现为:
<li class="row even">1</li> <li class="row odd">2</li> <li class="row even">3</li>
t-att=mapping如果参数是映射,则每个(键,值)对生成一个新属性及其值:
<div t-att="{'a': 1, 'b': 2}"/>
将呈现为:
<div a="1" b="2"></div>
t-att=pair如果参数是一对(元组或 2 个元素的数组),则该对的第一项是属性名称,第二项是值:
<div t-att="['a', 'b']"/>
将呈现为:
<div a="b"></div>
设置变量¶
QWeb 允许从模板内创建变量、记忆计算(多次使用)、为数据提供更清晰的名称,…
这是通过“set”指令完成的,该指令采用要创建的变量的名称。可以通过两种方式提供要设置的值:
包含表达式的
t-value属性,其计算结果将被设置:<t t-set="foo" t-value="2 + 1"/> <t t-out="foo"/>
将打印``3``
如果没有
t-value属性,则渲染节点的主体并将其设置为变量的值:<t t-set="foo"> <li>ok</li> </t> <t t-out="foo"/>
调用子模板¶
QWeb 模板可用于顶级渲染,但也可以使用“t-call”指令在另一个模板中使用它们(以避免重复或为模板的某些部分命名):
<t t-call="other-template"/>
如果 other_template 定义为:,这将使用父级的执行上下文调用命名模板:
<p><t t-value="var"/></p>
上面的调用将呈现为 <p/> (无内容),但是:
<t t-set="var" t-value="1"/>
<t t-call="other-template"/>
将呈现为“<p>1</p>”。
但是,这存在从外部可见的问题,“t-call`. Alternatively, content set in the body of the ``call`”指令将在调用子模板之前进行评估,并且可以更改本地上下文:
<t t-call="other-template">
<t t-set="var" t-value="1"/>
</t>
<!-- "var" does not exist here -->
call directive can be arbitrarily complex (not just set directives), and its rendered form will be available within the called template as a magical 0 变量的主体:
<div>
This template was called with content:
<t t-out="0"/>
</div>
被这样称呼:
<t t-call="other-template">
<em>content</em>
</t>
将导致:
<div>
This template was called with content:
<em>content</em>
</div>
高级输出¶
默认情况下,``out``应该对需要转义的内容进行HTML转义,保护系统免受XSS
不需要转义的内容将按原样注入到文档中,并且可能成为文档实际标记的一部分。
唯一的跨平台“安全”内容是与“主体”一起使用的 t-call 或 t-set 的输出(而不是 t-value or t-valuef)。
Python¶
通常您不必太关心:有意义的 API 应该自动生成“安全”内容,并且事情应该透明地工作。
对于需要更清晰的情况,以下 API 会输出安全内容,默认情况下,这些内容在注入模板时不会(重新)转义:
HTML fields。html_escape()和markupsafe.escape()(它们是别名,没有双重转义的风险)。html_sanitize()。markupsafe.Markup。警告
markupsafe.Markup是一个不安全的 API,它是一个*断言*,您希望内容是标记安全的,但不一定能够检查这一点,应谨慎使用。to_text()不会将内容标记为安全,但不会从安全内容中删除该信息。
强制双重转义¶
如果内容被标记为安全,但由于某种原因需要转义(例如打印 HTML 字段的标记),则可以将其转换回普通字符串以“剥离”安全标志,例如Python 中为 str(content) ,Javascript 中为 String(content) 。
注解
因为 Markup 是比 Markup() 丰富得多的类型,所以某些操作会从 Markup() 中删除安全信息,但不会从 Markup 中删除,例如Python 中的字符串连接('' + content)将产生 Markup ,而另一个操作数已被正确转义,而在 Javascript 中将产生 String() ,其中另一个操作数在连接之前*未*转义。
已弃用的输出指令¶
escout, would originally HTML-escape its input. Not yet formally deprecated as the only difference betweenoutandesc的别名是后者有点不清楚/不正确。rawout的一个版本*永远不会*转义其内容。内容按原样发出,无论安全与否。15.0 版后已移除: 请使用带有
markupsafe.Markup值的“out”。t-raw已被弃用,因为随着代码*生产*内容的发展,很难跟踪它将用于标记,从而导致更复杂的审查和更危险的失误。
Python¶
独家指令¶
资产包¶
“智能记录”字段格式¶
t-field directive can only be used when performing field access (a.b) on a “smart” record (result of the browse 方法)。它能够根据字段类型自动格式化,并集成在网站的富文本编辑中。
t-options can be used to customize fields, the most common option is widget,其他选项取决于字段或小部件。
调试¶
t-debug使用空值时,调用
breakpoint()内置函数,该函数通常调用调试器(默认情况下为pdb)。可以通过
PYTHONBREAKPOINT或sys.breakpointhook()配置该行为。
帮手¶
基于请求¶
QWeb 的大多数 Python 端使用都在控制器中(以及在 HTTP 请求期间),在这种情况下,存储在数据库中的模板(如 views)可以通过调用 odoo.http.HttpRequest.render() 轻松呈现:
response = http.request.render('my-template', {
'context_value': 42
})
这会自动创建一个 Response 对象,该对象可以从控制器返回(或进一步定制以适应)。
基于视图¶
比前一个帮助器更深的层次是``_render`` method on ir.qweb (use the datable) and the public module method ``render``(不使用数据库):
- _render(id[, values])¶
通过数据库 ID 或 external id 呈现 QWeb 视图/模板。模板会自动从“
ir.qweb”记录加载。_prepare_environmentmethod sets up a number of default values in the rendering context. Thehttp_routingandwebsiteaddons, also default values they need. You can useminimal_qcontext=Falseoption to avoid this default value like the public methodrender:request当前
Request对象(如果有)debug当前请求(如果有)是否处于``debug``模式
quote_plusurl 编码实用函数
json对应的标准库模块
time对应的标准库模块
datetime对应的标准库模块
- relativedelta
参见模块
keep_querykeep_query辅助函数
- 参数
values – 传递给 QWeb 进行渲染的上下文值
engine (str) – 用于渲染的 Odoo 模型的名称,可用于本地扩展或自定义 QWeb(通过基于“
ir.qweb”创建一个“新”qweb 并进行更改)
- render(template_name, values, load, **options)¶
load(ref)()返回 etree 对象,ref
JavaScript¶
独家指令¶
定义模板¶
t-name 指令只能放置在模板文件的顶层(将子项定向到文档根目录):
<templates>
<t t-name="template-name">
<!-- template code -->
</t>
</templates>
它不需要其他参数,但可以与“<t>` element or any other. With a <t> element, the ``<t>`”一起使用,应该有一个子项。
模板名称是任意字符串,尽管当多个模板相关时(例如称为子模板),通常使用点分隔的名称来指示层次关系。
模板继承¶
- 模板继承用于:
就地更改现有模板,例如将信息添加到模板
- 由其他模块创建。
从给定的父模板创建新模板
- 模板继承是通过使用两个指令来执行的:
t-inherit是要继承的模板的名称,t-inherit-modewhich is the behaviour of the inheritance: it can either be set toprimaryto create a new child template from the parented one or toextension来更改父模板。
还可以指定可选的“t-name”指令。如果在主要模式下使用,它将是新创建的模板的名称,否则它将作为注释添加到转换后的模板上,以帮助回溯继承。
对于继承本身,更改是使用 xpaths 指令完成的。有关完整的可用指令集,请参阅 XPATH 文档。
主继承(子模板):
<t t-name="child.template" t-inherit="base.template" t-inherit-mode="primary">
<xpath expr="//ul" position="inside">
<li>new element</li>
</xpath>
</t>
扩展继承(就地转换)::
<t t-inherit="base.template" t-inherit-mode="extension">
<xpath expr="//tr[1]" position="after">
<tr><td>new cell</td></tr>
</xpath>
</t>
旧的继承机制(已弃用)¶
模板继承是通过“t-extend”指令执行的,该指令将要更改的模板的名称作为参数。
指令 t-extend will act as a primary inheritance when combined with t-name 以及单独使用时作为扩展指令。
在这两种情况下,都会使用任意数量的“t-jquery”子指令来执行更改:
<t t-extend="base.template">
<t t-jquery="ul" t-operation="append">
<li>new element</li>
</t>
</t>
应用 t-jquery directives takes a CSS 选择器. This selector is used on the extended template to select context nodes to which the specified t-operation:
append节点的主体附加在上下文节点的末尾(在上下文节点的最后一个子节点之后)
prepend节点的主体被添加到上下文节点之前(插入到上下文节点的第一个子节点之前)
before节点的主体被插入到上下文节点之前
after节点的主体被插入到上下文节点之后
inner节点的主体替换上下文节点的子节点
replace节点的主体用于替换上下文节点本身
attributes节点的主体应该是任意数量的``attribute`` elements, each with a ``name``属性和一些文本内容,上下文节点的命名属性将被设置为指定值(如果已经存在则替换,如果不存在则添加)
- 无操作
如果没有``t-operation`` is specified, the template body is interpreted as javascript code and executed with the context node as
this警告
虽然比其他操作强大得多,但这种模式也更难调试和维护,建议避免使用
调试¶
javascript QWeb 实现提供了一些调试挂钩:
t-log接受一个表达式参数,在渲染期间计算表达式并使用
console.log记录其结果:<t t-set="foo" t-value="42"/> <t t-log="foo"/>
将在控制台打印
42t-debug在模板渲染期间触发调试器断点:
<t t-if="a_test"> <t t-debug=""/> </t>
如果调试处于活动状态,将停止执行(确切条件取决于浏览器及其开发工具)
t-js节点的主体是模板渲染期间执行的 JavaScript 代码。采用
contextparameter, which is the name under which the rendering context will be available in thet-js的主体:<t t-set="foo" t-value="42"/> <t t-js="ctx"> console.log("Foo is", ctx.foo); </t>
帮手¶
- core.qweb¶
(核心是``web.core`` module) An instance of
QWeb2.Engine()with all module-defined template files loaded, and references to standard helper objects_(underscore), ``_t``(翻译函数)和JSON_.core.qweb.render可用于轻松渲染基本模块模板
应用程序编程接口¶
- class QWeb2.Engine()¶
QWeb“渲染器”处理 QWeb 的大部分逻辑(加载、解析、编译和渲染模板)。
Odoo Web 在核心模块中为用户实例化一个,并将其导出到“
core.qweb”。它还将各个模块的所有模板文件加载到该 QWeb 实例中。A
QWeb2.Engine()也充当“模板命名空间”。- QWeb2.Engine.QWeb2.Engine.render(template[, context])¶
将先前加载的模板渲染为字符串,使用“
context”(如果提供)查找模板渲染期间访问的变量(例如要显示的字符串)。- 参数
template (
String()) – 要渲染的模板的名称context (
Object()) – 用于模板渲染的基本命名空间
- 返回
细绳
引擎公开了另一种在某些情况下可能有用的方法(例如,如果您需要一个单独的模板命名空间,在 Odoo Web 中,看板视图将获得自己的
QWeb2.Engine()实例,这样它们的模板就不会与更通用的“模块”模板发生冲突):- QWeb2.Engine.QWeb2.Engine.add_template(templates)¶
在 QWeb 实例中加载模板文件(模板的集合)。模板可以指定为:
- XML 字符串
QWeb 将尝试将其解析为 XML 文档,然后加载它。
- 一个网址
QWeb 将尝试下载 URL 内容,然后加载生成的 XML 字符串。
- 一个``Document`` or
Node QWeb 将遍历文档的第一层(提供的根的子节点)并加载任何命名模板或模板覆盖。
A
QWeb2.Engine()还公开了用于行为定制的各种属性:- QWeb2.Engine.QWeb2.Engine.prefix¶
用于在解析期间识别指令的前缀。一根绳子。默认情况下,“
t”。
- QWeb2.Engine.QWeb2.Engine.debug¶
将引擎置于“调试模式”的布尔标志。通常,QWeb 会拦截模板执行期间引发的任何错误。在调试模式下,它会让所有异常继续执行而不拦截它们。
- QWeb2.Engine.QWeb2.Engine.jQuery¶
模板继承处理期间使用的 jQuery 实例。默认为“
window.jQuery”。