暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Odoo的QWeb模板

Odoo哥 2020-04-16
1724

在odoo中,不管是前端的html页面,还是小部件的html片段,都是通过Qweb来进行模板渲染的。其实有关于html、xml的模板引擎有很多,只是在odoo中选用的是Qweb而已。所以这一节我们来详细介绍一下Qweb,给大家总结一个可以收藏备查的知识点。

首先Qweb是一个xml的模板引擎,为了区分正常的xml定义与模板的定义,所以在Qweb中设定以"t-"开头的属性是需要模板处理的内容,另外还有以"t"名称定义的占位元素节点,这类元素本身在渲染的时候不会生成html代码。

我们先来看一下怎么在模板中定义变量,并输出变量:

<t t-set="age" t-value="43"/>
<p><t t-esc="age"/></p>

第一行通过t-set来设置一个变量名age,后面的t-value表示这个变量的值。第二行输出一段html,通过t-esc属性来输出变量age的值,所以最后的输出内容是:

<p>43</p>

另外还有一个t-raw的输出定义,其与t-esc类似,只是不会对输出的内容进行html转义。


跟其它的模板引擎一样,Qweb也提供了用于渲染时的条件式判断和循环判断,我们先来看一下条件式判断的使用:

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

这是一个简单的条件式,通过t-if属性来进行定义,后面的condition是一个条件式,如果这个条件为true,则输出结果如下:

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

前面我们说过<t>只是一个占位元素,在输出的时候不会生成对应html片段。当这个条件为false,则输出结果如下:

<div>
</div>

我们也可以再做一些简化,不需要定义<t>元素,直接用如下的方法来实现:

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

Qweb还提供了比较复杂一点的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-elif可以有多个,而且还可以嵌套使用。如下图所示:

上图首先根据payment_status的不同状态进行了不同的处理,然后当payment_status为done时,又嵌套了一个t-if和t-else来进行不同的处理,一般在嵌套时,为了区分代码块的层次,这里会用到<t>元素来进行区分。


对于模板中的循环情况,QWeb也提供了一个t-foreach属性,该属性使用一个表达式返回要迭代的集合,第二个属性t-as提供用于迭代的“当前项”的名称:

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

上面的实例表示这是一个需要执行三次的循环,每次循环时,变量i分别会赋值为1,2,3,所以输出的时候,就会是如下的结果:

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

除了通过t-as传递的名称外,foreach还为各种情况提供了一些其他变量,我们常用的会有如下几个:

  • $as_index:当前迭代索引(迭代的第一项的索引为0)

  • $as_first:当前项目是否是迭代的第一个

  • $as_last:当前项目是否为迭代的最后一个

在t-foreach代码块中,也可以通过t-set来定义变量,这里有一个关系到变量作用域的问题,如果变量是在代码块中新创建的,则作用域只在代码块中有效,如果是在上下文环境定义的变量,在代码块中有重新赋值,同在代码块结束后,将重新改变上下文环境中的变量值,如下所示:

<t t-set="existing_variable" t-value="False"/>
<!-- 变量existing_variable设置为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和new_variable设置为true-->
</p>


<!-- 变量existing_variable的值还是为true-->
<!-- 变量new_variable在这里是undefined -->


Qweb可以通过计算获取元素的属性并输出到html片段中,这个主要是通过设置"t-att"属性来实现,主要的方式有三种:

  • t-att-$name:创建一个名为$name的属性,并将结果设置为该属性的值,如:

<div t-att-a="42"/>

输出的结果为:

<div a="42"></div>
  • t-attf-$name:与上一个相同,但参数是格式字符串,而不仅仅是表达式,如:

<t t-foreach="[1, 2, 3]" t-as="item">
<li t-attf-class="row {{ (item_index % 2 === 0) ? 'even' : 'odd' }}">
<t t-esc="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适用于通过模版来渲染html页面,实际应用中,有很多的页面可能大部分使用的模版是相同,只有少量差异。为了增加模版的通用性,我们可以把共用的部分的定义成一个个不同的模版,然后通过搭积木的方式,把几个不同的模板组合成一个新的页面。这里就关系到一个问题,怎么在一个模板中调用另一个模板?在Qweb中提供了一个指令t-call来操作,如:

<t t-call="other-template"/>

我们假设other-template名称的定义为:

<p><t t-value="var"/></p>

通过正常的方式渲染时,得到的结果是"<P></P>",因为渲染的时候变量var没有值。那我们再来看通过如下方式来调用:

<t t-set="var" t-value="1"/>
<t t-call="other-template"/>

这个时候返回的结果就是"<p>1</p>",所以这里我们可以看出,当前模板的变量定义作用域,是可以传导到被call的子模版中的。在这个例子中,变量var是一个全局的变量,除了可以在子模版中使用以外,在当前模板的其它地方也可以使用,有时候只想这个变量在子模板中使用,怎么办呢?我们也可以使用如下的方法,来指定变量只作用于子模板的调用范围:

<t t-call="other-template">
<t t-set="var" t-value="1"/>
</t>
<!-- 在这个位置,变量"var"是没有值的 -->

上面的例子中,call节点里面不仅仅是只能有t-set来赋值,也可以是任意的html片段,这段html会被赋值为一个特殊的变量"0",然后在子模版中可以通过"<t t-raw="0"/>来获取这一段代码。

比如other-template的定义是:

<div>
This template was called with content:
<t t-raw="0"/>
</div>

我们通过如下方式来调用:

<t t-call="other-template">
<em>content</em>
</t>

那我们得到的结果就是:

<div>
This template was called with content:
<em>content</em>
</div>


QWeb的大多数Python端用法是在控制器中(以及HTTP请求期间),在这种情况下,可以通过调用odoo.http.HttpRequest.render()来简单地呈现数据库中存储的模板:

response = http.request.render('my-template', {
'context_value': 42
})

最后,我们再来看一下怎么在odoo中定义一个新的模版:

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

t-name用来指定一个模版的名称,是任意的一个字符串,不会有其它的参数。在关联多个模板(例如称为子模板)时,习惯上使用点分隔的名称来表示层次关系。

在实际应用中,我们可以重新创建一个新的模版,也可以通过继承其它的模板,做出少量修改后来生成新的模板。模板的继承是通过t-extend来进行实现:

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

上面的定义没有使用t-name来指定新的模板名称,所以这个时候会直接修改base.template的内容,继承后的修改是通过t-jquery来定位节点内的元素,t-operation来决定修改方式。

t-jquery是一个CSS选择器,通过此选择器来获取指定的操作节点,t-operation有如下几种方式,来决定新的片段操作:

  • append:节点的主体附加在上下文节点的末尾(在上下文节点的最后一个子节点之后)

  • prepend:该节点的主体位于上下文节点之前(在上下文节点的第一个子节点之前插入)

  • before:该节点的主体被插入到上下文节点之前

  • after:该节点的主体被插入到上下文节点之后

  • inner:节点的主体替换了上下文节点的子节点

  • replace:节点的主体用于替换上下文节点本身

  • attributes:节点的主体应该是任意数量的属性元素,每个属性元素都具有name属性和一些文本内容,上下文节点的name属性将设置为指定的值(如果已经存在则替换为该值,或者如果不存在则添加)


以上是有关于Odoo中的Qweb知识点,建议大家可以收藏,以便需要的时候随时查看。

文章转载自Odoo哥,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论