Skip to content

Odoo Data Files: XML & CSV Loading Guide for Developers

DeployMonkey Team · March 22, 2026 13 min read

What Are Data Files?

Data files load records into Odoo during module installation or upgrade. They define: configuration settings, default categories, email templates, security rules, demo data, and any records your module needs to function. Listed in __manifest__.py under data or demo.

XML Data Files

Basic Record Creation

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <data>
        <record id="department_engineering" model="hr.department">
            <field name="name">Engineering</field>
        </record>

        <record id="department_sales" model="hr.department">
            <field name="name">Sales</field>
        </record>
    </data>
</odoo>

Field Types

<!-- Char/Text -->
<field name="name">My Record</field>

<!-- Integer/Float -->
<field name="sequence">10</field>
<field name="price">99.99</field>

<!-- Boolean -->
<field name="active" eval="True"/>

<!-- Date -->
<field name="date_start">2026-01-01</field>

<!-- Selection -->
<field name="state">draft</field>

<!-- Many2one (reference) -->
<field name="company_id" ref="base.main_company"/>
<field name="department_id" ref="department_engineering"/>

<!-- Many2many -->
<field name="tag_ids" eval="[(6, 0, [ref('tag_important'), ref('tag_urgent')])]" />

<!-- One2many -->
<field name="line_ids">
    <record id="line_1" model="my.model.line">
        <field name="name">Line 1</field>
        <field name="quantity">5</field>
    </record>
</field>

<!-- HTML -->
<field name="description" type="html">
    <p>Rich <b>HTML</b> content</p>
</field>

<!-- Binary (base64 file) -->
<field name="image" type="base64" file="my_module/static/img/logo.png"/>

eval Expressions

<!-- Python expressions -->
<field name="active" eval="True"/>
<field name="sequence" eval="10"/>

<!-- Reference to another record's ID -->
<field name="parent_id" eval="ref('my_module.parent_record')"/>

<!-- Many2many command tuples -->
<field name="group_ids" eval="[(4, ref('base.group_user'))]" />

<!-- Date computation -->
<field name="date" eval="(datetime.now() + relativedelta(days=30)).strftime('%Y-%m-%d')"/>

<!-- Conditional value -->
<field name="company_id" eval="ref('base.main_company') if ref('base.main_company') else False"/>

noupdate Flag

<!-- noupdate="1": records are created on install but NOT updated on upgrade -->
<data noupdate="1">
    <record id="email_template_welcome" model="mail.template">
        <field name="name">Welcome Email</field>
        <field name="subject">Welcome!</field>
        <field name="body_html"><p>Welcome to our platform.</p></field>
    </record>
</data>

<!-- noupdate="0" (default): records are updated on every upgrade -->
<data noupdate="0">
    <record id="menu_main" model="ir.ui.menu">
        <field name="name">Main Menu</field>
    </record>
</data>

When to Use noupdate

Use noupdate="1"Use noupdate="0"
Email templates (user may customize)Views (always managed by module)
Default categories/tagsMenu items
Cron jobs (user may change schedule)Security rules
Demo dataActions
Initial configuration valuesReport definitions

CSV Data Files

CSV is ideal for bulk data like access rules and simple records.

# security/ir.model.access.csv
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_my_model_user,my.model.user,model_my_model,base.group_user,1,1,1,0
access_my_model_admin,my.model.admin,model_my_model,base.group_system,1,1,1,1
# data/categories.csv
id,name,sequence
my_module.cat_electronics,Electronics,10
my_module.cat_clothing,Clothing,20
my_module.cat_food,Food & Beverage,30

__manifest__.py Ordering

'data': [
    # 1. Security first (access rules needed by other records)
    'security/ir.model.access.csv',
    'security/record_rules.xml',

    # 2. Data/seed records (categories, templates, etc.)
    'data/categories.xml',
    'data/email_templates.xml',
    'data/cron_jobs.xml',

    # 3. Views and actions
    'views/my_model_views.xml',
    'views/menu.xml',

    # 4. Reports
    'report/my_report.xml',
],
'demo': [
    # Demo data only loaded when demo mode is enabled
    'demo/demo_data.xml',
],

Special XML Elements

<!-- Delete a record -->
<delete model="ir.ui.menu" id="sale.menu_old_feature"/>

<!-- Function call -->
<function model="res.company" name="_init_settings"/>

<!-- Menuitem shortcut -->
<menuitem id="menu_root" name="My App" sequence="100"/>
<menuitem id="menu_list" name="Records" parent="menu_root"
          action="action_my_model"/>

<!-- Template (QWeb) -->
<template id="my_template">
    <div class="container">...</div>
</template>

Common Mistakes

  • Wrong file order in manifest — Security must come before data that references groups
  • Missing XML ID prefix — Always include module name when referencing: ref('my_module.record_id')
  • Using noupdate for views — Views should always update on upgrade (noupdate="0")
  • Forgetting CSV header — CSV must have the exact header format: id,name,model_id:id,...
  • XML encoding — Always use encoding="utf-8" in the XML declaration