Skip to main content

Using XML data files

Using XML data files

While CSV files provide a simple and compact format to represent data, XML files are more powerful and give more control over the loading process. For example, their filenames are not required to match the model to be loaded. This is because the XML format is much richer and more information regarding what to load can be provided through the XML elements inside the file.


We already used XML data files in the previous chapters. The user interface components, such as views and menu items, are, in fact, records that are stored in system models. The XML files in the modules are the means used to load these records into the instance database.
To showcase this, we will add a second data file to the library_app module, data/book_demo.xml, with the following content:
<?xml version="1.0"?> 
<odoo noupdate="1"> 
  <!-- Data to load -->
  <record model="res.partner" id="res_partner_huxley"> 
    <field name="name">Aldous Huxley</field> 
  </record> 
  <record model="library.book" id="library_book_bnw"> 
    <field name="name">Brave New World</field> 
    <field name="author_ids"
           eval="[(4, ref('res_partner_huxley'))]" /> 
    <field name="date_published">1932-01-01</field> 
  </record> 
</odoo> 
As usual, the new data file must be declared in the __manifest__.py file:
'demo': [
    'data/res.partner.csv',
    'data/library.book.csv',
    'data/book_demo.xml',
],
Similar to the CSV data file we saw in the previous section, this file also loads data into the Library Books Model.
XML data files have an <odoo> top element, inside of which we can have several <record> elements that correspond to the CSV data rows.

Note

The <odoo> top element in data files was introduced in version 9.0 and replaces the former <openerp> tag. A <data> section inside the top element is still supported, but it's now optional. In fact, now, <odoo> and <data> are equivalent, so we could use either one as top elements for our XML data files.
A <record> element has two mandatory attributes, model and id, for the external identifier for the record, and contains a  <field> tag for each field to write on.
Note that the slash notation in the field names is not available here; we can't use <field name="publisher_id/id">. Instead, the ref special attribute is used to reference external identifiers. We'll discuss the values of the relational to-many fields in a moment.
You may have noticed the noupdate="1" attribute in the top <odoo> element. This prevents the data records from being loaded on module upgrades so that any later edits to them are not lost.

The noupdate data attribute

When a module is upgraded, the data file loading is repeated, and the module's records are rewritten. It is important to keep in mind that this means that upgrading a module will overwrite any manual changes that might have been made to the module's data.

Note

Notably, if views were manually modified to add customization, these changes will be lost with the next module upgrade. To avoid this, the correct approach is to instead create inherited views with the changes we want to introduce.
This rewrite behavior is the default, but it can be changed so that some of the data is only imported at install time, and is ignored in later module upgrades. This is done using the noupdate="1" attribute in the <odoo> or <data> elements.
This is useful for data that is to be used as initial configuration but is expected to be customized later, because these manually made customizations will be safe from module upgrades. For example, it is frequently used for record access rules, allowing them to be adapted to implementation-specific needs.
It is possible to have more than one <data> section in the same XML file. We can take advantage of this to separate data to import only once, with noupdate="1", and data that can be re-imported on each upgrade, with noupdate="0".  noupdate="0" is the default, so we can just omit it if we prefer. Note that we need to have a top-level XML element, so in this case, we will use two <data> sections. They must be inside a top level <odoo>or <data> element.

Note

The noupdate attribute can be tricky when developing modules, because changes made to the data later will be ignored. One solution is to, instead of upgrading the module with the -u option, re-install it using the -i option. Reinstalling from the command line using the -i option ignores the noupdate flags on data records.

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

Note

Changes in Odoo 12 In the Developer Menu, when accessing View Metadata, the dialog box now also shows the value for the No Update flag, along with the record's XML ID. Furthermore, the No Update flag can be changed there by clicking on it.

Defining records in XML

In an XML data file, each <record> element has two basic attributes, id and model, and contains <field> elements that assign values to each column. The id attribute corresponds to the record's external identifier and the model attribute corresponds to the target model. The <field> elements have a few different ways to assign values. Let's look at them in detail.

Setting field values directly

The name attribute of a <field> element identifies the field to write on.
The value to write is the element content: the text between the field's opening and closing tag. For dates and date-times, eval attributes with expressions returning date or datetime objects will work. Returning strings with "YYYY-mm-dd" and "YYYY-mm-dd HH:MM:SS" will be properly converted. For boolean fields, the "0" and "False" values are converted to False, and any other non-empty values will be converted to True .

Note

Changes in Odoo 10 The way Boolean False values are read from data files is improved in Odoo 10. In previous versions, any non-empty values, including "0" and "False", were converted to True. Until Odoo 9, Boolean values should be set using the eval attribute, such as eval="False".

Setting values using expressions

A more elaborate alternative for setting a field value is the eval attribute. It evaluates a Python expression and assigns the result to the field.

The expression is evaluated in a context that, besides Python built-ins, also has some additional identifiers that are available to build the expression to evaluate.
To handle dates, the following Python modules are available: time, datetime, timedelta, and relativedelta. They allow you to calculate date values, something that is frequently used in demonstration and test data, so that the dates used are close to the module installation date. For more information about these Python modules, see the documentation at https://docs.python.org/3/library/datatypes.html.
For example, to set a value to yesterday, we will use the following code:
<field name="date_published" 
       eval="(datetime.now() + timedelta(-1))" /> 
Also available in the evaluation context is the ref() function, which is used to translate an external identifier into the corresponding database ID. This can be used to set values for relational fields. As an example, we can use it to set the value for publisher_id:
<field name="publisher_id" eval="ref('res_partner_packt')" /> 

Setting values on many-to-one relation fields

For many-to-one relation fields, the value to write is the database ID for the linked record. In XML files, we usually know the XML ID for the record, and we need to have it translated into the actual database ID.
One way is to use the eval attribute with a ref() function, like we just did in the previous section.
A simpler alternative is to use the ref attribute, which is available for <field> elements. Using it to set the value for the publisher_id many-to-one field, we would write the following:
<field name="publisher_id" ref="res_partner_packt" /> 

Setting values on to-many relation fields

For one-to-many and many-to-many fields, instead of a single ID, a list of related IDs is expected. Furthermore, several operations can be performed—we may want to replace the current list of related records with a new one, or append a few records to it, or even unlink some records.


To support write operations on to-many fields, we use a special syntax in the eval attribute. To write to 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 in the first element.
To overwrite the list of authors of a book, we would use the following code:
<field name="author_ids" 
       eval="[(6, 0, 
              [ref('res_partner_alexandre'), 
               ref('res_partner_holger')] 
              )]"
/> 
To append a linked record to the current list of the authors of a book, we would use the following code:
<field name="author_ids" 
       eval="[(4, ref('res_partner_daniel'))]"
/> 
The preceding examples are the most common. In both cases, we used just one command, but we could chain several commands in the outer list. The append (4) and replace (6) commands are the most used. In the case of the append (4), the last value of the tripled is not used and is not needed, so it can be omitted, as we did in the preceding code sample.
The complete list of available commands is as follows:
  • (0, _ , {'field': value}) creates a new record and links it to this one.
  • (1, id, {'field': value}) updates the values on an already linked record.
  • (2, id, _) removes the link to and deletes the id related record.
  • (3, id, _) removes the link to, but does not delete, the id related record. This is usually what you will use to delete related records on many-to-many fields.
  • (4, id, _) links an already existing record. This can only be used for many-to-many fields.
  • (5, _, _) removes all the links, without deleting the linked records.
  • (6, _, [ids]) replaces the list of linked records with the provided list.
The _ underscore symbol used in the preceding list represents irrelevant values, usually filled with 0 or False.

Note

The trailing irrelevant values can be safely omitted. For example, (4, id, _) can be used as (4, id).

Shortcuts for frequently used models

If we go back to Chapter 3, Your First Odoo Application, we will find elements other than <record> in the XML files, such as <act_window> and <menuitem>.
These are convenient shortcuts for frequently used models, with a more compact notation compared to the regular <record> elements. They are used to load data into base models, supporting the user interface, and will be explored in more detail later, in Chapter 10, Backend Views – Designing the User Interface.
For reference, these are the shortcut elements available, along with the corresponding models they load data into:
  • <act_window> is for the window action model, ir.actions.act_window
  • <menuitem> is for the menu items model, ir.ui.menu
  • <report> is for the report action model, ir.actions.report.xml
  • <template> is for QWeb templates stored in the ir.ui.view model

Note

Changes in Odoo 11The <url> tag was deprecated and removed. In previous versions, it was used to load records for the URL action model, ir.actions.act_url.
It is important to note that, when used to modify existing records, the shortcut elements overwrite all the fields. This differs from the <record> basic element, which only writes to the fields provided. So, for cases where we need to modify just a particular field of a user interface element, we should do it using a <record> element instead.

Other actions in XML data files

So far, we have seen how to add or update data using XML files. But XML files also allow you to delete data and execute arbitrary model methods. This can be useful for more complex date setups.

Deleting records

To delete a data record, we can use the <delete> element, providing it with either an ID or a search domain to find the target records.
For example, using a search domain to find the record to delete looks as follows:
<delete 
  model="res.partner" 
  search="[('id','=',ref('library_app.res_partner_daniel'))]" 
/>
If we know the specific ID to delete, we can use it with the id attribute instead. This was the case for the previous example, so it could also be written like this, for the same effect:
<delete model="res.partner" id="library_app.res_partner_daniel" /> 

Calling model methods

An XML file can also execute arbitrary methods during its load process through the <function> element. This can be used to set up demo and test data.
For example, the Notes app, which is bundled with Odoo, uses it to set up demonstration data:
<data noupdate="1"> 
<function  
   model="res.users"  
   name="_init_data_user_note_stages" 
   eval="[]" />
</data> 
This calls the _init_data_user_note_stages method of the res.users Model, passing no arguments. The argument list is provided by the eval attribute, which is an empty list in this case.


Comments

Popular posts from this blog

The message and activity features

The message and activity features Odoo has available global  messaging  and activity planning features, provided by the  Discuss  application, with technical name mail. The mail module provides the  mail.thread  abstract class that makes it simple to add the messaging features to any model, and the  mail.activity.mixin  that adds planned activity features. This was done in  Chapter 4 ,  Extending Modules , to explain how to inherit features from mixin abstract classes. To add these features, we need to add the mail dependency to the add-on module,  library_checkout , and then have the library checkout model class inherit from the abstract classes providing the following features. Edit the  'depends'  key in the  library_checkout/__manifest__.py   file, to add the mail module, shown as follows: Copy 'depends': ['library_member' , 'mail' ], And edit the  library_checkout/m...

Setting up an nginx reverse proxy

Setting up an nginx reverse proxy While Odoo itself can serve web pages, it's strongly recommended that there is a  reverse  proxy positioned in front of it. A reverse proxy acts as an intermediary that manages the traffic between clients sending requests and the Odoo servers responding to them. Using a reverse proxy has several benefits. On the security side, it can do the following: Handle (and enforce) HTTPS protocols to encrypt traffic Hide the internal network characteristics Act as an application firewall, limiting the URLs accepted for processing Also, on the performance side, it can provide the following significant improvements: Cached static content, hence reducing the load on the Odoo servers Compressed content to speed up loading time Act as a load balancer, distributing load between several servers Apache is a popular choice when considering a reverse proxy, although  nginx  is a recent alternative with good technical argumen...

The QWeb template language

The QWeb template language The  QWeb  parser looks for special directives in the templates and replaces them with dynamically generated HTML. These directives are XML element attributes and can be used in any valid tag or element, such as  <div> ,  <span> , or  <field> . Sometimes, we may want to use a QWeb directive but we don't want to place it in any of the XML elements in our template. For those cases, we have a  <t>  special element that can have QWeb directives, such as  t-if  or  t-foreach , but is silent and won't have any output on the final XML/HTML produced. The QWeb directives will frequently make use of evaluated expressions to produce different results, depending on the current record values. There are two different QWeb implementations: client-side JavaScript and server-side Python. The reports and website pages use the server-side Python implementation of QWeb. Kanban views us...