odoo Qweb 语法简要记录

整理Qweb基础语法,翻译自 https://www.odoo.com/documentation/13.0/reference/qweb.html

QWeb是Odoo使用的主要模板引擎。它是XML模板引擎,主要用于生成HTML片段和页面。


引出 <t> 标签 

模板指令被指定为以t-为前缀的XML属性,例如,用于条件判断的t-if,其元素和其他属性将直接呈现。有时候为了避免呈现元素,还提供了占位符元素<t>,该元素执行其指令,但不会自身生成任何输出。

当时用<t>标签时,如果这里的 condition 是 True

<t t-if="condition">
    <p>Test</p>
</t>

将会得到结果渲染到页面:

<p>Test</p>

而当使用其他标签(常规html标签,非 <t> 标签),如果这里的 condition 是 True

<div t-if="condition">
    <p>Test</p>
</div>

将会得到结果渲染到页面:

<div>
    <p>Test</p>
</div>

<t> 标签就是用来干这事的。


输出指令

Qweb 有两个输出指令,一个主要的输出指令 t-esc ,和一个 伪输出指令 t-raw 。两者的区别:t-esc 输出的是数据库的原始值,t-raw ,不会对特殊符号转义,会将内容里的标签一起渲染到页面。

实践为证,执行SQL,查看数据库里存了个啥:

select e_link from zerone_book where id = 1

 看到结果:

 分别使用 t-esc 和 t-raw 输出:

<t t-esc="item.e_link"/>
<t t-raw="item.e_link"/>

 渲染结果:


条件判断指令

Qweb使用 t-if 做条件判断。

<div>
    <t t-if="condition">
        <p>ok</p>
    </t>
</div>

 如果条件 condition = True,会得到以下结果渲染到页面:

<div>
    <p>ok</p>
</div>

 如果条件 condition =False,会得到以下结果渲染到页面:

<div>
</div>

条件渲染适用于指令的载体,而该载体不必是<t>,得到的渲染结果是一样的:

<div>
    <p t-if="condition">ok</p>
</div>

另外,还提供了附加的条件分支指令t-elif和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 有一个迭代指令 t-foreach,用来接受一个返回集合进行迭代的表达式。它还有个指令 t-as,用来表示迭代的“当前项”的名称:

<t t-foreach="[1, 2, 3]" t-as="i">
    <p><t t-esc="i"/></p>
</t>

得到渲染结果:

<p>1</p>
<p>2</p>
<p>3</p>

像条件判断指令一样,t-foreach 适用于指令的载体,而该载体不必是<t>,得到的渲染结果是一样的:

<p t-foreach="[1, 2, 3]" t-as="i">
    <t t-esc="i"/>
</p>

t-foreach 可以在数组(当前项为当前值)或映射(当前项为当前键)上进行迭代。


属性

QWeb可以即时计算属性,并在输出节点上设置计算结果。 这可以通过t-att(属性)指令完成,该指令以3种不同形式存在:

t-att-$name 

创建一个名为$name的属性,计算属性值并将结果设置为属性值:

<div t-att-a="42"/>
<div t-att-style="color:red;"/>

得到渲染结果如下:

<div a="42"/>
<div style="color:red;"/>

t-attf-$name

 和前面一样,但参数是一个格式字符串,而不仅仅是表达式,通常用于混合文字和非文字字符串:

<t t-foreach="[1, 2, 3]" t-as="item">
    <li t-attf-class="row style_{{item}}">
        <t t-esc="item"/>
    </li>
</t>

得到渲染如下:

<li class="row style_1">1</li>
<li class="row style_2">1</li>
<li class="row style_3">1</li>

注 *  在 t-attf-* 指令中使用上下文变量时,可以使用双花括号 {{ }} 进行字符串的拼接

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允许在模板中创建变量,记忆一个计算(多次使用),给一块数据起一个更清晰的名字等。

通过指令 t-set 实现,一般情况下,赋值使用 t-value ,像下面这样:

<t t-set="foo" t-value="2 + 1"/>
<t t-esc="foo"/>

将会在对应dom位置渲染出 3 。

在不使用 t-value 的情况下,将会渲染节点的主体,并将其设置为变量的值,像这样:

<t t-set="foo">
    <li>ok</li>
</t>
<t t-esc="foo"/>

在对应dom位置,渲染出 <li>ok</li> ,  <li>ok</li> 就相当于 t-value 的值。


调用子模板

QWeb模板可用于顶层渲染,但也可以使用指令 t-call 在另一个模板中使用它们(以避免重复或为模板的各个部分命名)

一个 template 好像只会渲染第一个 <t t-name=""> ,在我亲测中(odoo13),如果像下面这样:

<template id="template1">
    <t t-name="old-template">
        <p>template-1</p>
    </t>

    <t t-name="new-template">
        <p>template-2</p>
        <t t-call="old-template"/>
    </t>
</template>

得到渲染结果:

<p>template-1</p>

只在页面中,渲染出第一个 <t t-name="old-template"> 的内容,后面的 <t t-name = 'new-template' > 被忽略掉了。

所以,我将它们分别写到不同的 template 里,我在odoo13中,测试 t-call 的使用,t-call 的值应是 被调用子模板所在的template的 id ,代码如下:

<template id="template1">
    <t t-name="old-template">
        <p>template-1</p>
    </t>
</template>

<template id="template2">
    <t t-call="模块名.template1"/>
    <t t-name="new-template">
        <p>template-2</p>
    </t>
</template>

 

字段

t-field 此指令 不能 在 t 标签中使用

# 此接口返回3条最新新闻
@http.route('/news/top/3')
def zerone_retrun_3_top_news(self, **kwargs)
    recs = http.request.env["zerone.news"].sudo().search([], order="id desc", limit=3)
    return http.request.render('zerone.new3_news',{'news':recs})
<template id="new3_news">
    <t t-foreach="news" t-as="item">
        <a t-att-href="item.href"><p t-field="item.title"/></a>
    </t>
</template>

渲染出:

<a href="url1"><p>title1</p></a>
<a href="url2"><p>title2</p></a>
<a href="url3"><p>title3</p></a>

t-options 可用于自定义字段,最常见的选项是小部件,其他选项依赖于字段或小部件。


定义模板

使用 t-name 伪指令只能放在模板文件的顶层(将子级直接指向文档根目录):

<templates>
    <t t-name="template-name">
        <!-- template code -->
    </t>
</templates>

模板继承

模板继承用于改变现有的模板,例如,将信息添加到其他模块创建的模板中。

模板继承是通过t-extend指令执行的,该指令以要更改的模板名称作为参数。

当t-extend与t-name结合使用时,将创建一个具有给定名称的新模板。

在这种情况下,扩展模板不会更改,相反,伪指令定义了如何创建新模板。

在这两种情况下,都可以使用任意数量的t-jquery子伪指令执行更改:

<t t-extend="base.template">
    <t t-jquery="ul" t-operation="append">
        <li>new element</li>
    </t>
</t>

t-jquery指令采用CSS选择器。 在扩展模板上使用此选择器来选择要应用指定t操作的上下文节点。

  • append    节点的主体附加在上下文节点的末尾(在上下文节点的最后一个子节点之后)
  • prepend   节点的主体位于上下文节点之前(在上下文节点的第一个子节点之前插入)
  • before      节点的主体被插入到上下文节点之前
  • after         节点的主体被插入到上下文节点之后
  • inner        节点的主体替换了上下文节点的子节点
  • replace    节点的主体用于替换上下文节点本身
  • attributes 节点的主体应该是任意数量的属性元素,每个属性元素都具有name属性和一些文本内容,上下文节点的named属性将设置为指定的值(如果已经存在则替换为该值,或者如果不存在则添加

其他

t-log 接受一个表达式参数,在渲染过程中计算该表达式,并使用console.log记录其结果: 

<t t-set="foo" t-value="42"/>
<t t-log="foo"/>

将输出42

t-debug  在模板渲染期间触发调试器断点:

<t t-if="a_test">
    <t t-debug="">
</t>

如果调试处于活动状态,则将停止执行(具体条件取决于浏览器及其开发工具)。

t-js 节点的主体是在模板渲染期间执行的javascript代码。 带有一个上下文参数,该名称是渲染上下文在t-js主体中可用的名称:

<t t-set="foo" t-value="42"/>
<t t-js="ctx">
    console.log("Foo is", ctx.foo);
</t>


最后最后,如果有同学发现那里不对,在下方留言,贴出你的demo ,因为 odoo 官方文档挺老了,我能动手的确实有限。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章