Development Book V18: Data Loading

Odoo provides several mechanisms to load data into yourk database during module installation. Whether you're initializing master data, defining access rights, or executing methods, you can leverage XML and CSV files to automate these operations.

Loading Data Using XML Files

XML files are the most common way to define and load data in Odoo modules. You typically place them in a data/ directory inside your custom module.

Basic XML Record Structure

                       <record model="model.name" id="record_id">
    <field name="field_name">value</field>
</record> 
  • model: The technical name of the model (e.g., res.partner)
  • id: A unique identifier for the record within this module (used as an XML ID)
  • field: Each field to set for this record

Example: Creating a Contact Record

To define a contact record using XML, create a file res_partner_data.xml in the data/ directory of your module (e.g., custom_contacts).

<odoo>
    <data>
        <record id="partner_1" model="res.partner">
            <field name="name">Aby Wills < /field>
            < field name="phone">9865432344 < /field>
            < field name="email">aby@example.com < /field>
        </record > 
    </data > 
</odoo>

Then, reference it in your __manifest__.py file:

'data': [
    'data/res_partner_data.xml',
],

Once you install the module, the contact will be created automatically in the system.

Loading Data Using CSV Files

CSV files are ideal for importing large volumes of data or defining access control lists (ACLs).

Format and Structure

  • The file should be named after the model (e.g., ir.model.access.csv)
  • The first row lists field names, including id (external ID)
  • Each following row represents one record

Example: account.tax.group.csv

id,name,country_id/id
tax_group_0,TVA 0%,base.lu
tax_group_3,TVA 3%,base.lu
tax_group_6,TVA 6%,base.lu

When the module is installed, records will be inserted into the account.tax.group model.

noupdate: Preserve Data on Module Update

The noupdate="1" attribute ensures that Odoo doesn't re-apply the data when the module is upgraded. This is useful for preserving user-modified records.

<odoo>
    <data noupdate="1">
        <record id="res_partner_data" model="res.partner">
            <field name="name">Demo Partner</field>
            <field name="email">demo@gmail.com</field>
        </record>
    </data>
</odoo>

Once created, this partner will not be updated in future upgrades, even if the XML changes.

forcecreate: Always Ensure Creation

The forcecreate="1" attribute forces record creation only if it doesn't exist yet. This avoids duplication and ensures idempotency.

<record forcecreate="True" id="decimal_payment" model="decimal.precision">
    <field name="name">Payment Terms</field>
    <field name="digits">6</field>
</record>

Odoo will create this record only if one with the same XML ID doesn't already exist.

Understanding External IDs

External IDs (also called XML IDs) are persistent identifiers used by Odoo to manage data records created via XML/CSV.

  • Format: module_name.record_id (e.g., sale.mail_act_sale_upsell)
  • Used to update existing records during module updates

Example:

<record id="base.main_company" model="res.company">
    <field name="name">My Company (San Francisco)</field>
</record>

This updates the name of the company record with ID base.main_company.

You can view any record’s External ID via Developer Tools > View Metadata in debug mode.

Namespaces in External IDs

If an external ID contains exactly one dot (.), Odoo treats the part before the dot as the module name (namespace).

<record id="product.decimal_precision" model="decimal.precision"<
    <field name="name">Product UoM</field<
</record<

If no dot is present, Odoo automatically prepends the current module name.

Deleting Records Using XML

You can remove previously created records using the tag in two ways:

1. Delete by Domain

<delete model="product.category" id="demo_category_1"/>

This will delete the record with external ID demo_category_1 from the product.category model

2. Delete by Domain

   <delete model="sale.order" search="[('partner_id.name', '=', 'Azure Interior')]"/>

This deletes all sale.order records where the partner name is “Azure Interior”. Be cautious — this can affect user-entered data.

Calling Python Functions from XML

Odoo allows you to execute methods at module install time using the tag.

1. Without Parameters

   <function id="func_call" model="product.product" name="func_without_params"/>
   class Product(models.Model):
    _inherit = "product.product"

    @api.model
    def func_without_params(self):
        self.create({'name': 'Test'})

2. With Parameters

<function id="func_call_with_params" model="product.product" name="func_with_params">
    <value>Cybrosys Technologies</value>
</function>
class Product(models.Model):
    _inherit = "product.product"

    @api.model
    def func_with_params(self, name):
        self.create({'name': name})

You can also pass domains or evaluated expressions using the eval attribute:

<value eval="[('name', '=', 'My Product'), ('active', '=', True)]"/>
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