QWeb - это основной генератор шаблонов, используемый Odoo[#othertemplates] _. Это генератор шаблонов XML[#genshif] _ и используется в основном для генерации HTML-фрагментов и страниц.
Директивы шаблона задаются в виде атрибутов XML с префиксом t-
, например t-if
для Условия, при котором элементы и другие атрибуты выводятся напрямую.
Чтобы избежать рендеринга элементов, также доступен элемент-заполнитель <t>
, который выполняет свою директиву, но не генерирует никакого вывода сам по себе:
<t t-if="condition">
<p>Test</p>
</t>
Создаст HTML следующего вида:
<p>Test</p>
Если condition
являет true, но:
<div t-if="condition">
<p>Test</p>
</div>
Создаст HTML следующего вида:
<div>
<p>Test</p>
</div>
Вывод данных
QWeb имеет основную директиву вывода, которая автоматически выводит HTML-контент, ограничивающий риски XSS при отображении пользовательского контента: esc
.
esc
принимает выражение, оценивает его и печатает содержимое:
<p><t t-esc="value"/></p>
генерируется HTML со значением value
, равным 42
, и на выходе получится следующее:
<p>42</p>
Есть еще одна директива вывода raw
, которая ведет себя так же, как и esc
, но не очищает HTML-вывод. Может быть полезно отображать специально созданную разметку (например, из функций) или уже обработанную пользовательскую разметку.
Условия
У 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
(attribute), которая существует в 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-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"/>
будет сгенерировано
<li>ok</li>
(содержимое экранируется, так как мы использовали директиву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
, будет выполнен до вызова суб-шаблона и может изменить локальный контекст
<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>
Создаст HTML следующего вида:
<div>
This template was called with content:
<em>content</em>
</div>
Python
Эксклюзивные директивы
Бандлы ассетов
форматирование полей «смарт записей»
Директива t-field
может быть использована только при выполнении доступа к полям (a.b
) с помощью «смарт записи» (результат метода browse
). Результат работы директивы автоматически форматируется в зависимости от типа поля и выводится в HTML в виде отформатированного текста.
t-options
можно использовать для настройки полей, наиболее распространенной опцией является widget
, другие опции зависят от поля или виджета.
Отладка
t-debug
Вызывает отладчик с помощью API-интерфейса PDB
set_trace
. Параметр должен быть именем модуля, в котором вызывается методset_trace
:<t t-debug="pdb"/>
эквивалентно
importlib.import_module("pdb").set_trace()
Помощники
Основанные на запросах
Большинство сценариев использования QWeb на стороне Python находятся в контроллерах (и во время выполнения HTTP-запросов). В этом случае шаблоны, хранящиеся в базе данных (как views), могут быть отрендерены вызовом метода 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 или external id. Шаблоны автоматически загружаются из записей модели ir.ui.view
.
Устанавливает ряд значений по умолчанию в контексте рендеринга:
request
- текущий объект
WebRequest
, если таковой имеется debug
- будет ли текущий запрос выполняться (если существует) в режиме
debug
quote_plus
- функция утилиты url-encoding
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-extend
, которая принимает имя изменяемого шаблона в качестве параметра.
Когда t-extension
объединяется с 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-operation
:
append
- тело элемента добавляется в конец контекстного элемента (после последнего дочернего элемента контекстного элемента)
prepend
- тело элемента добавляется к элементу контекста (вставляется перед первым дочерним элементом контекстного элемента)
before
- тело элемента вставляется непосредственно перед элементом контекста
after
- тело элемента вставляется сразу после элемента контекста
inner
- тело элемента замещает дочерние элементы контекстного элемента
replace
- тело элемента используется для замены самого элемента контекста
attributes
- Тело узлов должно состоять из любого количества элементов
attribute
, каждый из которых имеет атрибутname
и текстовый контент; для именованного атрибута узла контекста будет установлено указанное значение (либо заменяется, если оно уже существовало или добавлено если нет) - No operation
если не указано `` t-operation``, тело шаблона интерпретируется как javascript-код и выполняется с контекстным элементом как
this
Предупреждение
хотя она гораздо более мощная, чем другие операции, данный режим намного сложнее отлаживать и поддерживать, поэтому мы рекомендуем избегать его
Отладка
В реализации QWeb для javascript есть несколько отладочных инструментов:
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
(сore это модуль web.core
). Экземпляр QWeb2.Engine()
со всеми загруженными файлами шаблонов определенных в модулях и ссылки на стандартные вспомогательные объекты _
(подчеркивание), _t
(функция перевода) и JSON.
с помощью функции core.qweb.render
можно легко отрендерить базовые шаблоны модулей
API
class QWeb2.Engine()
QWeb «renderer», обрабатывает большую часть логики QWeb (загрузка, парсинг, компиляция и рендеринг шаблонов).
OpenERP Web создает экземпляр для пользователя и устанавливает его в core.qweb
. Он также загружает все файлы шаблонов различных модулей в этот экземпляр QWeb.
Класс QWeb2.Engine()
также служит в качестве пространства имен для шаблонов.
QWeb2.Engine.QWeb2.Engine.render(template[, context])
Отправляет ранее загруженный шаблон в String, используя context
(если имеется), чтобы найти переменные, к которым обращался при рендеринге данного шаблона (например, строки для отображения).
- template (
String
) – имя шаблона для рендеринга - context (
Object
) – основное пространство имен, используемое для рендеринга шаблона
Генератор шаблонов предоставляет другой метод, который может быть полезен в некоторых случаях (например, если вам нужно отдельное пространство имен для ваших шаблонов, в OpenERP Web, представление Kanban получит свой собственный класс QWeb2.Engine()
, чтобы их шаблоны не пересекались с основными шаблонами «модулей»):
QWeb2.Engine.QWeb2.Engine.add_template(templates)
Загружает файл шаблона (коллекцию шаблонов) в экземпляр QWeb. Шаблоны могут быть указаны как:
- Строка XML
- QWeb попытается произвести его парсинг в документ XML, а затем загрузить его.
- URL-адрес
- QWeb попытается загрузить содержимое URL, а затем загрузить полученную XML-строку.
Document
илиNode
- 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
Function
. Если присутствует, вызывается перед компиляцией каждого узла DOM в код шаблона. В Odoo Web это используется для автоматического перевода текстового содержимого и некоторых атрибутов в шаблонах. По умолчанию используется null
.