Enable Dark Mode!
overview-of-qweb-templates-and-operations-in-odoo-19.jpg
By: Vishnu P

Overview of Qweb Templates and Operations in Odoo 19

Technical Odoo 19 Odoo Enterprises Odoo Community

Odoo’s QWeb templating system is the core for building front-end views, reports, website pages, and various dynamic HTML/XML outputs. In Odoo 19, QWeb has matured further, offering more operations and directives to control rendering, caching, conditions, loops, inheritance, sub-templates, and more.

In this article, we’ll walk through the most important QWeb features and operations in Odoo 19: how to output data, use conditionals, loops, attributes, variables, sub-templates, caching, and some advanced/custom operations. By the end, you should be comfortable authoring or customizing QWeb templates in Odoo.

What is QWeb?

QWeb is the templating engine used in Odoo for rendering HTML/XML from templates with embedded directives. It is used in:

  • Website frontends and portal pages
  • The website builder
  • Email templates
  • PDF and Excel reports
  • Backend UI components

Templates are defined with t- directives (attributes prefixed with t-) and special tags. The template is parsed and rendered, resolving variables, loops, and conditions dynamically.

Basic QWeb Templates

A basic QWeb template defines reusable HTML/XML markup that can display dynamic data passed from Odoo models or controllers.

<template id="hello_template">
   <div>
       <h2>Hello, <t t-esc="user.name"/>!</h2>
   </div>
</template>

Templates can be rendered from controllers, reports, or views, making them highly flexible across Odoo’s ecosystem.

Basic Data Output

To insert data into a QWeb template, you use:

  • t-esc — for escaped output (default; safe against HTML injection)
  • t-raw — for raw/unescaped output (use carefully)
  • t-out — older/deprecated directive; use t-esc or t-raw instead.
<t t-esc="partner.name"/>
<t t-raw="partner.description"/>

Also, there is support for “smart record fields formatting,” where QWeb automatically handles formatting of Odoo fields (dates, money, relations) based on field definitions.

Conditionals

Use t-if, t-elif, and t-else to show content based on conditions.

  • t-if — conditional inclusion if expression is true
  • t-elif — else-if
  • t-else — fallback
<t t-if="user.is_admin">
 <p>Welcome, admin!</p>
</t>
<t t-else="">
 <p>Welcome, user!</p>
</t>

Loops (Foreach)

To repeat content for each item in a list, use t-foreach with t-as.

<t t-foreach="orders" t-as="order">
 <div>
   <span t-esc="order.name"/>
   <span t-esc="order.amount_total"/>
 </div>
</t>

Inside loops, you can use t-if/t-esc etc. The loop introduces a scope for the variable (order above).

Setting Attributes and Variables

You often need to conditionally set HTML attributes or create temporary variables.

Dynamic Attributes

Use t-att to dynamically set one or more attributes in a QWeb template.

<span t-att-class="'badge ' + ('success' if status == 'done' else 'warning')">
   <t t-esc="status"/>
</span>

Temporary Variables

t-set — define a variable in template scope. Example:

<t t-set="full_name" t-value="user.first_name + ' ' + user.last_name"/>
<p t-esc="full_name"/>

Sub-Templates and Template Inheritance

Sub-Templates

Define reusable chunks of templates with <template> and call them using t-call.

<template id="my_template">
 <p t-esc="message"/>
</template>
<template id="other">
 <t t-call="my_template">
   <t t-with="{'message': 'Hello from call'}"/>
 </t>
</template>

Inheritance

Templates can inherit from other templates, replacing or extending parts. Odoo uses xpath expressions for identifying parts to be replaced/inserted. There is an old inheritance mechanism (deprecated) and the newer mechanism. You typically use something like:

<template inherit_id="base.template_to_inherit">
 <xpath expr="//div[@class='header']" position="inside">
   <p>New content in header</p>
 </xpath>
</template>
Inheritance allows modules to customize existing templates without duplicating.

Dynamic QWeb Rendering

QWeb templates can also be rendered dynamically in Python or controllers.

from odoo import http
class MyController(http.Controller):
   @http.route('/hello', auth='public')
   def hello(self, **kw):
       return http.request.render('my_module.hello_template', {
           'user': http.request.env.user,
       })

This enables fully dynamic page rendering or API responses using QWeb.

QWeb in Reports

Odoo uses QWeb as the report engine for PDF, HTML, and XLSX formats.

<template id="report_order_document">
   <t t-call="web.html_container">
       <t t-foreach="docs" t-as="o">
           <h2 t-esc="o.name"/>
           <p>Total: <t t-esc="o.amount_total"/></p>
       </t>
   </t>
</template>

Report registration in XML:

<report
   id="action_report_order"
   model="sale.order"
   string="Sales Order"
   report_type="qweb-pdf"
   name="my_module.report_order_document"
/>

QWeb in Emails

Odoo’s mail templates use QWeb for dynamic message rendering:

<t t-name="mail_template_order">
   <p>Hello <t t-esc="object.partner_id.name"/>,</p>
   <p>Your order <t t-esc="object.name"/> has been confirmed.</p>
</t>

Email templates can use variables such as:

  • object > the current record
  • user > the logged-in user
  • ctx > context variables

This makes it easy to generate personalized messages automatically

QWeb in Website Pages

QWeb powers Odoo’s website and portal templates. It allows rendering dynamic content directly in pages.

<template id="website_sale_products" name="Products">
   <t t-foreach="products" t-as="product">
       <div class="product-card">
           <h3 t-esc="product.name"/>
           <span t-esc="product.list_price"/>
       </div>
   </t>
</template>

In Controller:

@http.route('/products', auth='public')
def products(self):
   products = http.request.env['product.template'].search([])
   return http.request.render('my_module.website_sale_products', {'products': products})

Advanced Output: Python, Escaping, Deprecated Directives

  • You can embed Python expressions in directives (e.g. inside t-if, t-value, etc). However, logic should be minimal in templates. Heavy business logic still belongs to models or controllers.
  • Double-escaping / forcing escape: sometimes you need to ensure that content is escaped even if raw, or handle special characters safely. QWeb helps avoid XSS vulnerabilities.
  • Deprecated directives: some old output directives are deprecated. For example, t-out is old; use t-esc or t-raw. The docs warn about certain deprecated behaviors.

Caching: t-cache, t-nocache, Scoped Caching

Rendering large templates or repeating parts can be expensive. Caching directives allow reusing rendered fragments.

  • t-cache: cache the result of a template fragment based on input variables. If the same inputs occur again, the engine uses the cached rendering. Very useful for static or rarely changing data.
  • t-nocache: the opposite; ensures part is always freshly rendered (not from cache). Use when dynamic content must always reflect the latest state.

Also, caching interacts with scope and variable binding: if you have loops or sub-templates inside cache, scoping rules matter. The docs cover “What if there is a t-cache inside a t-cache?”, “base of t-cache,” “t-nocache and scoped root values,” etc.

Helpers, Debugging, Best Practices

  • Helpers: QWeb has helper functions for formatting fields (dates, monetary, relational fields), which know about field type metadata. Makes template output more consistent.
  • Debugging: The docs describe how to inspect/enable debugging, how to view template inheritance chain, locate where a given snippet comes from, etc. Useful when templating issues arise.
  • Best Practices:
    • Keep logic in the Python/model side. Templates should be mainly for presentation.
    • Use t-esc unless you absolutely have safe HTML content.
    • Use template inheritance for customization rather than copying templates.
    • Make use of caching for performance, but be careful: dynamic content needs no caching or proper invalidation.
    • Use clear variable names, and wrap complex logic in helper methods in the model rather than inline expressions.
<template id="order_card">
 <t t-set="is_high_value" t-value="order.amount_total > 1000"/>
 <div t-attrs='{"class": "order-card " + (" high" if is_high_value else "")}'>
   <h2 t-esc="order.name"/>
   <p>Customer: <t t-esc="order.partner_id.name"/></p>
   <p t-if="is_high_value">?? High value order!</p>
   <div>
     <t t-foreach="order.order_line" t-as="line">
       <div>
         <span t-esc="line.product_id.display_name"/> — qty: <t t-esc="line.qty"/>
       </div>
     </t>
   </div>
 </div>
</template>

QWeb in Odoo 19 is a powerful templating system, giving developers the tools to render dynamic content cleanly and efficiently. By using its directives smartly—output statements, loops, conditionals, attributes, sub-templates, inheritance, and caching—you can build UI, website pages, and report templates that are maintainable, performant, and secure.

To read more about What is Qweb Templates & Key Features of Qweb in Odoo 18, refer to our blog What is Qweb Templates & Key Features of Qweb in Odoo 18.


If you need any assistance in odoo, we are online, please chat with us.



0
Comments



Leave a comment



whatsapp_icon
location

Calicut

Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635

location

Kochi

Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.

location

Bangalore

Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message