Ir al contenido

Ficheros XML/CSV de datos: noupdate, orden y shortcuts

Por qué falla la instalación y cómo hacer datos idempotentes
7 de julio de 2026 por
Ficheros XML/CSV de datos: noupdate, orden y shortcuts
Atemi, Aitor Atencia

Odoo · Módulos · Datos

"Funcionaba en mi máquina" tiene una variante muy odoica: "se instaló bien la primera vez, pero al actualizar el módulo se ha duplicado todo". Casi siempre es un problema de noupdate, de orden de carga o de un ID mal referenciado en los ficheros de datos.

Logo Odoo Logo XML
Los ficheros de datos son código: se versionan, se revisan y también pueden tener bugs.

La opción por defecto

noupdate="1": protege los datos frente a futuras actualizaciones

Cuando un fichero XML se marca con noupdate="1", sus registros se crean en la instalación pero no se vuelven a tocar en actualizaciones posteriores del módulo, aunque el XML cambie en el código. Es el comportamiento correcto para datos que el usuario puede personalizar después: secuencias, plantillas de email, datos demo.

<odoo>
  <data noupdate="1">
    <record id="mail_template_bienvenida" model="mail.template">
      <field name="name">Bienvenida cliente</field>
      <field name="subject">Bienvenido/a</field>
    </record>
  </data>
</odoo>

Lo que sí se actualiza siempre

Vistas, menús y acciones: sin noupdate

Las vistas, menús, grupos de seguridad y acciones normalmente van sin noupdate="1" (o con noupdate="0", el valor por defecto), precisamente porque queremos que un -u las actualice cuando cambian en el código. Mezclar ambos tipos de datos en el mismo fichero es la fuente más común de confusión.

<odoo>
  <!-- Sin noupdate: se actualiza en cada -u -->
  <record id="view_mi_modelo_form" model="ir.ui.view">
    <field name="name">mi.modelo.form</field>
    <field name="model">mi.modelo</field>
    <field name="arch" type="xml">
      <form><field name="name"/></form>
    </field>
  </record>
</odoo>

El orden importa

El manifest carga los ficheros en orden, no alfabético

Odoo procesa la lista data del __manifest__.py en el orden literal en que aparece. Si un registro referencia (vía ref o env.ref()) un ID que todavía no se ha creado, la instalación falla con un ValueError: External ID not found.

Orden recomendadoMotivo
1. security/*.csv y gruposLas vistas y menús suelen referenciar grupos de seguridad
2. data/*.xml (secuencias, datos base)Los registros de negocio pueden depender de ellos
3. views/*.xmlReferencian modelos y grupos ya cargados
4. data/mail_template_data.xml, demo/*.xmlSuelen referenciar vistas o plantillas previas

Cuando el volumen es grande

CSV como shortcut para datos masivos

Para catálogos grandes (códigos postales, categorías, datos maestros con cientos de filas), un CSV es mucho más legible que XML repetitivo. La primera columna siempre es id (el external ID) y el resto son los nombres técnicos de los campos.

# data/res_partner_category.csv
id,name,color
categoria_vip,Cliente VIP,1
categoria_moroso,Moroso,2
categoria_nuevo,Nuevo,5
# __manifest__.py
"data": [
    "security/ir.model.access.csv",
    "data/res_partner_category.csv",
    "views/res_partner_views.xml",
],

Idempotencia real

Por qué reinstalar no debería duplicar nada

El external ID (id en XML/CSV) es lo que garantiza idempotencia: si el registro ya existe con ese ID, Odoo lo actualiza (o lo ignora si está en noupdate); si no existe, lo crea. El problema aparece cuando un desarrollador crea datos vía código Python (create() en un hook de instalación) sin comprobar antes si ya existen, generando duplicados en cada reinstalación.

# Mal: duplica en cada reinstalación
def post_init_hook(env):
    env["res.partner.category"].create({"name": "Cliente VIP"})

# Bien: idempotente, usa el external ID
def post_init_hook(env):
    env["res.partner.category"]._load_records([{
        "xml_id": "mi_modulo.categoria_vip",
        "values": {"name": "Cliente VIP"},
        "noupdate": True,
    }])

Resumen

La mayoría de fallos de instalación y duplicados en Odoo se explican por tres cosas: usar noupdate="1" donde toca (y no donde no toca), respetar el orden de carga del manifest para que los ref siempre encuentren su objetivo, y usar external IDs también desde Python cuando se crean datos por código.

en Odoo
Monitorización: logs, Grafana y alertas en un stack Odoo
Promtail, Loki, métricas y umbrales de WARNING que sí importan