Шаблони QWeb

QWeb є основною системою templating, яку використовує Odoo2. Це система шаблонів XML1, яка використовується переважно для генерування HTML фрагментів і сторінок.

Директиви шаблону вказуються як XML-атрибути з префіксом t-, наприклад 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 has a primary output directive which automatically HTML-escape its content limiting XSS risks when displaying user-provided content: esc.

esc takes an expression, evaluates it and prints the content:

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

відтворено зі значенням value встановленим на 42 дає:

<p>42</p>

There is one other output directive raw which behaves the same as respectively esc but does not HTML-escape its output. It can be useful to display separately constructed markup (e.g. from functions) or already sanitized user-provided markup.

Умовні

QWeb має умовну директиву if, яка обчислює вираз, поданий як значення атрибута:

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

Елемент відображається, якщо умова - true:

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

але якщо умова - 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 має директиву ітерації 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>

Як і умови, foreach застосовується до елемента, що несе атрибут директиви, і

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

еквівалентний попередньому прикладу.

foreach може повторювати масив (поточний елемент буде поточним значенням) або відображення (поточний елемент буде поточним ключем). Ітерація цілого числа (еквівалентна ітерації масиву від 0 включно до наданого виняткового цілого числа) все ще підтримується, але не підтримується.

На додаток до імені, переданого через t-as, foreach надає кілька інших змінних для різних точок даних:

Попередження

$as буде замінено іменем, переданим t-as

$as_all (застаріле)

об’єкт, який повторюється

Примітка

Ця змінна доступна лише на JavaScript QWeb, а не на Python.

$as_value

поточне значення ітерації, ідентичне $as для списків і цілих чисел, але для відображень воно надає значення (де $as надає ключ)

$as_index

індекс поточної ітерації (перший елемент ітерації має індекс 0)

$as_size

розмір колекції, якщо вона доступна

$as_first

чи є поточний елемент першим у ітерації (еквівалентно $as_index == 0)

$as_last

чи є поточний елемент останнім у ітерації (еквівалентно $as_index + 1 == $as_size), вимагає наявності розміру ітерованого

$as_parity (застаріле)

або "even" або "odd", парність поточного циклу ітерації

$as_even (застаріле)

логічний прапор, який вказує, що поточний раунд ітерації має парний індекс

$as_odd (застаріле)

логічний прапор, який вказує, що поточний раунд ітерації має парний індекс

Ці надані додаткові змінні та всі нові змінні, створені в foreach, доступні лише в області foreach. Якщо змінна існує поза контекстом 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

те саме, що й попередній, але параметр є формат рядка, а не просто виразом, часто корисним для змішування літерального та нелітерального рядків (наприклад, класів):

<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 дозволяє створювати змінні з шаблону, запам’ятовувати обчислення (використовувати його кілька разів), давати фрагменту даних чіткішу назву, …

Це робиться за допомогою директиви set, яка приймає назву змінної для створення. Значення для встановлення можна надати двома способами:

  • атрибут t-value, що містить вираз, і результат його оцінки буде встановлено:

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

    надрукує 3

  • якщо атрибут t-value відсутній, тіло вузла відображається та встановлюється як значення змінної:

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

    згенерує &lt;li&gt;ok&lt;/li&gt; (вміст екранується, оскільки ми використовували директиву esc)

    Примітка

    використання результату цієї операції є важливим варіантом використання директиви raw.

виклик підшаблонів

Шаблони 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. Крім того, вміст, встановлений у тілі директиви call, буде оцінено before викликом підшаблону та може змінити локальний контекст:

<t t-call="other-template">
    <t t-set="var" t-value="1"/>
</t>
<!-- "var" does not exist here -->

Тіло директиви call може бути як завгодно складним (не тільки директиви ``set), і її відтворена форма буде доступна в шаблоні виклику як магічна змінна 0:

<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>

Python

Ексклюзивні директиви

Пакети активів

форматування полів «розумних записів»

Директиву t-field можна використовувати лише під час виконання доступу до поля (a.b) для «розумного» запису (результат методу browse). Він здатний автоматично форматувати на основі типу поля та інтегрований у редагування форматованого тексту веб-сайту.

t-options можна використовувати для налаштування полів, найпоширенішим варіантом є widget, інші параметри залежать від полів або віджетів.

Налагодження

t-debug

викликає налагоджувач за допомогою API set_trace PDB. Параметр має бути назвою модуля, для якого викликається метод set_trace:

<t t-debug="pdb"/>

еквівалентний importlib.import_module("pdb").set_trace()

Помічники

На основі запитів

Більшість QWeb на стороні Python використовується в контролерах (і під час HTTP-запитів), у цьому випадку шаблони, що зберігаються в базі даних (як представлення), можуть бути тривіально відтворені викликом odoo.http.HttpRequest.render():

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

Це автоматично створює об’єкт Response, який можна повернути з контролера (або додатково налаштувати відповідно до нього).

На основі представлення

На глибшому рівні, ніж попередній помічник, знаходиться метод render на ir.ui.view:

render(cr, uid, id[, values][, engine='ir.qweb][, context])

Відтворює представлення/шаблон QWeb за ідентифікатором бази даних або зовнішній id. Шаблони автоматично завантажуються із записів ir.ui.view.

Встановлює ряд значень за замовчуванням у контексті візуалізації:

request

поточний об’єкт WebRequest, якщо такий є

debug

чи поточний запит (якщо є) знаходиться в режимі debug

quote_plus

функція утиліти кодування url

json

відповідний модуль стандартної бібліотеки

time

відповідний модуль стандартної бібліотеки

datetime

відповідний модуль стандартної бібліотеки

relativedelta

переглянути модуль

keep_query

допоміжна функція keep_query

Параметри
  • values – значення контексту для передачі в QWeb для візуалізації

  • engine (str) – ім’я моделі Odoo для використання для рендерингу, можна використовувати для локального розширення або налаштування QWeb (шляхом створення «нового» qweb на основі ir.qweb зі змінами)

Javascript

Ексклюзивні директиви

Визначення шаблонів

Директиву t-name можна розмістити лише на верхньому рівні файлу шаблону (направляти дітей до кореня документа):

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

Він не приймає інших параметрів, але може використовуватися з елементом <t> або будь-яким іншим. З елементом <t> елемент <t> повинен мати єдиного дочірнього елемента.

Назва шаблону - це довільний рядок, хоча, коли кілька шаблонів пов’язано (наприклад, підшаблони), прийнято використовувати розділені крапками імена для позначення ієрархічних зв’язків.

Спадкування шаблонів

Успадкування шаблону використовується для:
  • Змінювати існуючі шаблони на місці, напр. щоб додати інформацію до шаблонів

створені іншими модулями.
  • Створіть новий шаблон із заданого батьківського шаблону

Успадкування шаблону виконується за допомогою двох директив:
  • t-inherit, це назва шаблону для успадкування,

  • t-inherit-mode, який є поведінкою успадкування: його можна встановити як primary, щоб створити новий дочірній шаблон із батьківського, або extension, щоб змінити батьківський шаблон на місці.

Також можна вказати необов’язкову директиву 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 діятиме як первинне успадкування в поєднанні з 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

тіло вузла має бути будь-якою кількістю елементів attribute, кожен з атрибутом name і деяким текстовим вмістом, іменований атрибут вузла контексту буде встановлено на вказане значення (або замінено, якщо воно вже існувало або додано, якщо ні)

Без операції

якщо t-operation не вказана, тіло шаблону інтерпретується як код javascript і виконується з контекстним вузлом як this

Попередження

хоча цей режим набагато потужніший за інші операції, він також набагато важчий для налагодження та підтримки, рекомендується уникати його

налагодження

Реалізація javascript QWeb надає кілька гачків для налагодження:

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, який виконується під час візуалізації шаблону. Приймає параметр context, який є назвою, під якою контекст візуалізації буде доступний у тілі t-js:

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

Помічники

core.qweb

(ядро - це модуль web.core) Екземпляр QWeb2.Engine() із завантаженими всіма визначеними модулем файлами шаблонів і посиланнями на стандартні допоміжні об’єкти _ (підкреслення), _t (функція перекладу) і JSON.

core.qweb.render можна використовувати для легкого відтворення основних шаблонів модулів

API

class QWeb2.Engine()

«Рендеринг» QWeb обробляє більшість логіки QWeb (завантаження, аналіз, компіляція та візуалізація шаблонів).

Odoo Web створює екземпляр для користувача в основному модулі та експортує його до core.qweb. Він також завантажує всі файли шаблонів різних модулів у цей екземпляр QWeb.

QWeb2.Engine() також служить «простором назв шаблону».

QWeb2.Engine.QWeb2.Engine.render(template[, context])

Відтворює попередньо завантажений шаблон у рядок, використовуючи context (якщо надається) для пошуку змінних, до яких звертаються під час відтворення шаблону (наприклад, рядки для відображення).

Аргументи
  • template (String()) – назва шаблону для візуалізації

  • context (Object()) – основний простір назв для відтворення шаблону

Повертає

рядок

Механізм надає інший метод, який може бути корисним у деяких випадках (наприклад, якщо вам потрібен окремий простір імен шаблону з, в Odoo Web, представлення Kanban отримують власний екземпляр QWeb2.Engine(), тому їх шаблони не стикаються з більш загальними шаблонами «модулів»):

QWeb2.Engine.QWeb2.Engine.add_template(templates)

Завантажує файл шаблону (набір шаблонів) в примірник QWeb. Шаблони можна вказати як:

Рядок XML

QWeb спробує розібрати його до документа XML, а потім завантажити.

URL

QWeb спробує завантажити вміст URL-адреси, а потім завантажити отриманий рядок XML.

Документ або Вузол

QWeb пройде перший рівень документа (дочірні вузли наданого кореня) і завантажить будь-який названий шаблон або перевизначення шаблону.

QWeb2.Engine() також надає різні атрибути для налаштування поведінки:

QWeb2.Engine.QWeb2.Engine.prefix

Префікс, який використовується для розпізнавання директив під час аналізу. Рядок. За замовчуванням t.

QWeb2.Engine.QWeb2.Engine.debug

Логічний прапор, що переводить движок у «режим налагодження». Зазвичай QWeb перехоплює будь-яку помилку, яка виникає під час виконання шаблону. У режимі налагодження він залишає всі винятки проходити без їх перехоплення.

QWeb2.Engine.QWeb2.Engine.jQuery

Екземпляр jQuery, який використовується під час обробки успадкування шаблону. За замовчуванням window.jQuery.

QWeb2.Engine.QWeb2.Engine.preprocess_node

Функція. Якщо є, викликається перед компіляцією кожного вузла DOM у код шаблону. В Odoo Web це використовується для автоматичного перекладу текстового вмісту та деяких атрибутів у шаблонах. За замовчуванням null.

1

він схожий на Genshi, хоча не використовує (і не підтримує) простори назв XML

2

хоча він використовує кілька інших, або з історичних причин, або тому, що вони залишаються кращими для використання. Odoo 9.0 все ще залежить від Jinja і Mako.