整理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 官方文檔挺老了,我能動手的確實有限。