OD323 duplicate-xmlid-across-files¶
A data file defines an XML id another file of the module already defines, with another model, or overwriting the fields both name.
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Correctness | Warning | all | no |
What it reports¶
An XML id of the module, with or without the module's own prefix, that a loaded data file defines after another loaded file, when the later definition:
- has another model than the record, so it cannot update that record;
- is a
<template>, a<menuitem>or any other tag that stands for a record, except a<template>withforcecreatefalse; - is a
<record>, or a CSV row, that writes only fields the earlier files already write.
A <template> without id takes its XML id from t-name, so it repeats an id like any other.
OD303 covers the same id twice in one file.
Why it matters¶
Among definitions of one model, an install writes every one, noupdate or not, and works field by
field. The later definition finds the record under its id and writes only the fields it names, so
nothing fails. A field it does not name keeps its value. On install, a field both definitions name
ends up with the later value, so a different value in the earlier file is gone with no message, and
an equal one changes nothing. groups on a <menuitem>, and up to 16.0 on a <report> or
<act_window>, is the exception: the tag links the groups it lists and unlinks those marked -, so
a menu keeps the groups of both definitions. A tag names the fields Odoo builds from it, which can
be more than it spells out: a <menuitem> outside another one and without parent clears the
parent, from 11.0 without active sets it true, and without name takes its action's name or its
id. Without action it keeps the action.
The rule does not compare values, so it reports both cases. The usual cause is a block copied to a new file whose id was not renamed. Remove the copy when the two say the same thing, since renaming it would give the database a second, identical record. Rename one when both are meant to exist. A definition of another model cannot be a copy, so its only fix is to rename one.
On install, Odoo refuses a definition of another model from saas~15.2, and from October 2022 on
13.0, 14.0 and 15.0, with a ValidationError before any write. Through saas~11.4 an assert
refuses it, but only when the new model's table has a row with the earlier record's database id.
From saas~11.5 until the ValidationError arrives, that unrelated record of the new model is
overwritten and the load goes on. Without such a row, on any of these series, the XML id moves to a
new record and the earlier record stays with no XML id.
The rule stays silent on what reads as a deliberate update:
- A
<record>that writes a field the earlier files do not, or writes nothing at all. A later definition that adds one field and changes another stays silent too. - A
<record>or<template>of the same model that setsforcecreateto false. Other tags drop it and are reported with it. It does not stop a write to a record that exists: the rule takes it as the author's word that the record is meant to be updated. - A field written with x2many commands that keep the other rows, codes 0 to 4 or
Command.create,update,delete,unlinkandlink, and a field holding nested records. - A
<record>of the same model after a tag.
It also stays silent on:
- A demo file on either side: demo data is expected to update what the data created.
- An id prefixed with another module, which belongs to that module.
- An id a
<function model="ir.model.data" name="_update_xmlids">call assigns. - A file the manifest does not load.
Example¶
<odoo>
<record id="view_tier_form" model="ir.ui.view">
<field name="name">tier.form</field>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<form><field name="name"/></form>
</field>
</record>
</odoo>
<odoo>
<record id="view_tier_form" model="ir.ui.view">
<field name="name">tier.list</field>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<list><field name="name"/></list>
</field>
</record>
</odoo>
Both files name name and arch with different values, so the second file turns the form into a
list, and the module ends up with one view.
<odoo>
<record id="view_tier_list" model="ir.ui.view">
<field name="name">tier.list</field>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<list><field name="name"/></list>
</field>
</record>
</odoo>
The id is new, so both views exist. Had the second file repeated the form, the fix would be to delete its record.