Skip to content

Data Binding & Expressions

One of the most powerful features of Omni Designer is its seamless integration with your Odoo data model. Unlike cumbersome XML QWeb reports, you can browse and bind data visually.

The Data tab in the sidebar shows the complete field schema of the model your report is based on (e.g., sale.order).

Screenshot placeholder
Data Tab showing the field schema of sale.order
  • Standard Fields: Name, Date, Amount, etc.
  • Relational Fields (Many2one): Expand these (like partner_id) to access fields of the related record (e.g., partner_id.name, partner_id.email).
  • Collection Fields (One2many, Many2many): Represent lists of records (like order_line). These are used with Section or Table components for repeating data.

Use the search bar at the top of the Data tab to quickly filter and find fields. Click the collapse button to fold all expanded nodes back.

Video placeholder
Dragging fields from the Data tab onto the canvas
  1. Simple Field: Drag a standard field (like name) onto a blank area. Omni Designer reads the field type and creates a Field component bound to that data path.
  2. Collection Field: If you drag a One2many/Many2many field (like order_line), the designer can automatically create a repeating Section containing the inner fields.

Behind the scenes, dynamic data is resolved using expressions. You can view or write these manually in the Property Panel under the element’s content property.

The primary expression syntax uses ${ } delimiters:

  • Simple field: ${name}
  • Deep path: ${partner_id.name}
  • Math: ${amount_total * 1.1}
  • Conditional: ${amount > 0 ? "Positive" : "Negative"}

For more complex text where you want to mix static text with multiple dynamic values, you can use Mustache-style syntax with {{ }} delimiters:

  • Invoice #{{name}} {{partner_id.name}}

The expression engine includes a rich library of built-in functions. You can use these in any expression field.

FunctionSignatureDescription
lenlen(s)Returns the length of a string, list, or map
upperupper(s)Converts string to uppercase
lowerlower(s)Converts string to lowercase
strstr(x)Converts value to string representation
formatformat(fmt, ...)Formats a string with {0}, {1} placeholders
stripstrip(s)Removes leading and trailing whitespace
replacereplace(s, old, new)Replaces occurrences of a substring
splitsplit(s, delimiter)Splits string by delimiter
joinjoin(separator, list)Joins list elements with separator
FunctionSignatureDescription
roundround(x, n)Rounds x to n decimal places
absabs(x)Returns absolute value
floorfloor(x)Largest integer ≤ x
ceilceil(x)Smallest integer ≥ x
minmin(...)Returns the smallest item
maxmax(...)Returns the largest item
sumsum(list)Returns sum of all items
averageaverage(list)Returns average of all items
countcount(list)Returns number of items in list
FunctionSignatureDescription
intint(x)Converts value to integer
floatfloat(x)Converts value to float
boolbool(x)Converts value to boolean
decimaldecimal(x)Converts value to decimal number
FunctionSignatureDescription
sortedsorted(list)Returns a new sorted list
reversedreversed(seq)Returns a reversed sequence
anyany(list, x => expr)True if predicate matches any item
allall(list, x => expr)True if predicate matches all items
countIfcountIf(list, x => expr)Counts items where predicate is truthy
firstfirst(list)Returns first element (null if empty)
lastlast(list)Returns last element (null if empty)
FunctionSignatureDescription
datetime.timedeltadatetime.timedelta(days=0, hours=0, ...)Creates a duration for date arithmetic
OperatorDescriptionExample
+ - * / %Arithmetic5 + 38
== != < >Comparisonamount > 0true
&& || !Logical AND, OR, NOTa && b
? :Ternary (If-Else)x > 0 ? "Yes" : "No"

When you use a Section component to iterate over a list of records (e.g., Data Source = order_line), the context inside that section changes.

Elements inside the section resolve expressions relative to the current row they are rendering:

  • Inside an order_line Section, ${name} evaluates to the line’s description, not the parent order’s name.
  • To reference the parent record from within a Section, use the full path from the root context.
Video placeholder
Section data context and field resolution

Every element has a Visibility property section. You can provide an expression here that must evaluate to a truthy value (true, non-zero, non-empty text) for the element to render.

Screenshot placeholder
Visibility condition editor
  • Example: ${state == 'sale'} the element only renders if the order is in “Sale” state.
  • Combine conditions: ${amount_total > 1000 && state == 'sale'}
  • This is ideal for conditionally hiding discount columns, tax summaries, or special disclaimers.

Beyond visibility, each element supports Dynamic Styles conditional formatting rules that change the appearance of an element based on data.

For example:

  • Turn the text red when ${amount < 0}
  • Add a yellow background when ${priority == 'urgent'}

Rules are managed through the Dynamic Styles section in the property panel. See the Components Reference for more details.