XML data files

While CSV files provide a simple and compact format to serialize data, XML files are more powerful and give more control over the loading process.

We have already used XML data files in the previous chapters. The user interface components, such as views and menu items, are in fact records stored in system models. The XML files in the modules are a means used to load those records into the server.

To showcase this, we will add a second data file to the todo_user module, named todo_data.xml, with the following content:

<?xml version="1.0"?>
<openerp>
  <data>
    <!-- Data to load -->
    <record model="todo.task" id="todo_task_c">
      <field name="name">Reinstall Odoo</field>
      <field name="user_id" ref="base.user_root" />
      <field name="date_deadline">2015-01-30</field>
    </record>
  </data>
</openerp>

This XML is equivalent to the CSV data file we have just seen in the previous section.

XML data files have a <openerp> element containing <data> elements, inside of which we can have have several <record> elements, corresponding to the CSV data rows.

A <record> element has two mandatory attributes, model and id (the external identifier for the record), and contains a <field> tag for each field to write on.

Note that the slash notation in field names is not available here: we can't use <field name="user_id/id">. Instead the ref special attribute is used to reference External IDs. We'll discuss the values for the relational "to many" fields in a moment.

The data noupdate attribute

When the data loading is repeated, existing records from the previous run are rewritten.

This is important to keep in mind: it means that upgrading a module will overwrite any manual changes that might have been made to the data. Notably, if views were modified with customizations, those changes will be lost with the next module upgrade. The correct procedure is to instead create inherited views for the changes we need, as discussed in the Chapter 3, Inheritance – Extending Existing Applications.

This overwrite behavior is the default, but it can be changed, so that when an already created record is loaded again no change is made to it. This is done by adding to the <data> element a noupdate="1" attribute. With this, its records will be created the first time they are loaded, and in subsequent module upgrades nothing will be done to them.

This allows for manually made customizations to be safe from module upgrades. It is often used with record access rules, allowing them to be adapted to implementation specific needs.

It is also possible to have more than one <data> section in the same XML file. We can take advantage of this to have a data set with noupdate="1" and another with noupdate="0".

The noupdate flag is stored in the External Identifier information for each record. It's possible to edit it directly using the External Identifier form available in the Technical menu, with the Non Updatable checkbox.

Tip

The noupdate attribute is tricky when developing modules, because changes made to the data later will be ignored, and Odoo won't pick up later modifications. A solution is to keep noupdate="0" during development and only set it to 1 once finished.

Defining Records in XML

Each <record> element has two basic attributes, id and model, and contains <field> elements assigning values to each column. As mentioned before, the id attribute corresponds to the record's External ID and the model to the target model where the record will be written. The <field> elements have available a few different ways to assign values. Let's look at them in detail.

Setting field values

The <record> element defines a data record, and contains <field> elements to set values on each field.

The name attribute of the field element identifies the field to be written.

The value to write is the element content: the text between the field's opening and closing tag. In general this is also suitable to set non-text values: for Booleans, "0"/ "1" or "False"/"True" values will be correctly converted; for dates and datetimes, strings with "YYYY-MM-DD" and "YYYY-MM-DD HH:MI:SS" will be converted properly.

Setting values using expressions

A more advanced alternative to define a field value is using the eval attribute instead. This evaluates a Python expression and assigns the resulting value to the field.

The expression is evaluated in a context that, besides Python built-ins, also has some additional identifiers available. Let's have a look at them.

To handle dates, the following modules are available: time, datetime, timedelta and relativedelta. They allow calculating date values, something that is frequently used in demonstration (and test) data. For example, to set a value to yesterday we would use:

<field name="expiration_date"
   eval="(datetime.now() + timedelta(-1)).strftime('%Y-%m-%d')" />

Also available in the evaluation context is the ref() function, used to translate an External ID into the corresponding database ID. This can be used to set values for relational fields. As an example, we have used it before to set the value for the user_id:

<field name="user_id" eval="ref('base.group_user')" />

The evaluation context also has a reference available to the current Model being written through obj. It can be used together with ref() to access values from other records. Here is an example from the Sales module:

<value model="sale.order"
  eval="obj(ref('test_order_1')).amount_total" />

Setting values for relation fields

We have just seen how to set a value on a many-to-one relation field, such as user_id, using the eval attribute with a ref() function. But there is a simpler way.

The <field> element also has a ref attribute to set the value for a many-to-one field using an External ID. Using it, we can set the value for user_id using just:

<field name="user_id" ref="base.group_user" />

For one-to-many and many-to-many fields, a list of related IDs is expected, so a different syntax is needed, and Odoo provides a special syntax to write on this type of fields.

The following example, taken from the Fleet app, replaces the list of related records of a tag_ids field:

<field name="tag_ids"
  eval="[(6,0,   
    [ref('vehicle_tag_leasing'),
    ref('fleet.vehicle_tag_compact'),
    ref('fleet.vehicle_tag_senior')]
)]" />

To write on a to many-field we use a list of triples. Each triple is a write command that does different things according to the code used:

  • (0,_ ,{'field': value}): This creates a new record and links it to this one
  • (1,id,{'field': value}): This updates values on an already linked record
  • (2,id,_): This unlinks and deletes a related record
  • (3,id,_): This unlinks but does not delete a related record
  • (4,id,_): This links an already existing record
  • (5,_,_): This unlinks but does not delete all linked records
  • (6,_,[ids]): This replaces the list of linked records with the provided list

The underscore symbol used above represents irrelevant values, usually filled with 0 or False.

Shortcuts for frequently used Models

If we go back to Chapter 2, Building Your First Odoo Application, we can find in the XML files elements other than <record>, such as <act_window> and <menuitem>.

These are convenient shortcuts for frequently used Models that can also be loaded using regular <record> elements. They load data into base Models supporting the user interface and will be explored in more detail later, in Chapter 6, Views - Designing the User Interface.

For reference, so that we can better understand XML files we may encounter in existing modules, the following shortcut elements are available with the corresponding Models they load data into:

  • <act_window>: This is the Window Actions model ir.actions.act_window
  • <menuitem>: This is the Menu Items model ir.ui.menu
  • <report>: This is the Report Actions model ir.actions.report.xml
  • <template>: This is View QWeb Templates stored in model ir.ui.view
  • <url>: This is the URL Actions model ir.actions.act_url

Other actions in XML data files

Until now we have seen how to add or update data using XML files. But XML files also allow performing other types of actions, sometimes needed to set up data. In particular, they are capable in deleting the data, execute arbitrary model methods, and trigger workflow events.

Deleting records

To delete a data record we use the <delete> element, providing it with either an id or a search domain to find the target record.

In Chapter 3, Inheritance – Extending Existing Applications, we had the need to remove a record rule added by the to-do app. In the todo_user/security/todo_access_rules.xml file a <delete> element was used, with a search domain to find the record to delete:

<delete
   model="ir.rule"
   search="[('id','=',ref('todo_app.todo_task_user_rule'))]"
/>

In this case the same exact effect could be achieved using the id attribute to identify the record to delete:

<delete model="ir.rule" id="todo_app.todo_task_user_rule" />

Triggering functions and workflows

An XML file can also execute methods during its load process through the <function> element. This can be used to set up demo and test data. For example, in the membership module it is used to create demonstration membership invoices:

<function
  model="res.partner"
  name="create_membership_invoice"   
  eval="(ref('base.res_partner_2'),
    ref('membership_0'),
    {'amount':180})"
/>

This is calling the create_membership_invoice() method of the res.partner model. The arguments are passed as a tuple in the eval attribute. In this case we have a tuple with three arguments: the Partner ID, the Membership ID and a dictionary containing the invoice amount.

Another way XML data files can perform actions is by triggering Odoo workflows, through the <workflow> element.

Workflows can, for example, change the state of a sales order or convert it into an invoice. Here is an example taken from the sale module, converting a draft sales order to the confirmed state:

<workflow model="sale.order"
          ref="sale_order_4"
          action="order_confirm" />

The model is self-explanatory by now, and ref identifies the workflow instance we are acting upon. The action is the workflow signal sent to that workflow instance.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset