OD324 missing-required-field¶
A data record is created without a required field that has no default.
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Correctness | Warning | all | yes |
What it reports¶
A <record> or a CSV row that Odoo creates, leaving out a stored field with required=True and no
default in any class of the model, its _inherit parents and mixins included. A record creates
when it has no id, or when its id is the module's own and nothing before it defines that id.
When a record leaves the field of an _inherits parent empty, Odoo creates that parent, so a required
field of the parent counts too, unless the record names the parent through the delegating field.
The rule reads a demo file like any other. A failure there costs the module its demo data from saas~11.5, and stops the install before: see load failures. Writes in later files fill nothing: Odoo creates the record at its first definition.
Why it matters¶
The value reaches the INSERT as NULL, and on a NOT NULL column PostgreSQL stops the load of the
file with null value in column ... violates not-null constraint. The field is usually one added to
the model after the data was written.
The severity is a Warning because this is a medium confidence finding: a pre_init_hook, an init()
method or an SQL file can fill the column in ways the scan does not read. When an _inherit adds
such a field to a table holding rows, they stay NULL, SET NOT NULL fails, Odoo only logs it, and
the INSERT stores NULL.
The rule stays silent when something may give the value:
- A
defaulton any definition of the field, acomputeor arelated, whether stored or not. - A
defaulton an_inheritschild's own definition of a parent field, withinherited=True. A child field withoutinheritedonly shadows the parent's and gives it nothing. - A
default_<field>key in thecontextof the record or of an<odoo>or<data>around it. - A literal
<function model="ir.default" name="set">in a module in scope. One in a demo file only counts for records in demo files, since it loads after the data. default_get,create,load,_add_missing_default_values,_prepare_create_values,_load_recordsor_load_records_createon the model, or on a parent class whose model has the field. Which keys they set is not read.- The inverse field of a record nested in a one2many.
sequenceandxmlid, which the loader may fill itself._defaultsthrough 9.0. A method called_default_xmeans nothing withoutdefault=.
It stays silent in these cases, where the record creates nothing or the column has no constraint:
- An id prefixed with another module, a later definition, an id a module in scope wrote first, and
ids Odoo generates:
model_*,field_*and the ids of_inheritsparents of records Odoo loads. A demo write counts as written first only for a record in a demo file, as a database may hold no demo data. - Any id of
base, whichbase_data.sqlcreates before the data, and a CSV row with a.id. - An id'd record after a
<function>of the module, which may have created it. - A record in a module with an unread data file, or that depends on one, since that file may have created it.
forcecreatefalse, and a record nested in a field other than a one2many.- A One2many, a Many2many, a Binary or an Image field, a company-dependent field, a field that is not
stored, and a model with
_auto = False. - A delegating field left empty, since Odoo fills it with the parent it creates.
- A file the manifest does not load.
- A field only a module outside the scope adds, a module with a dependency that is not indexed, a module that builds model names at runtime, and a model with a parent the scan cannot see.
Example¶
class Tier(models.Model):
_name = "x.tier"
_description = "Tier"
name = fields.Char(required=True)
code = fields.Char(required=True)
<odoo>
<record id="tier_gold" model="x.tier">
<field name="name">Gold</field>
</record>
</odoo>
Nothing gives code, so the install stops on the INSERT.
<odoo>
<record id="tier_gold" model="x.tier">
<field name="name">Gold</field>
<field name="code">gold</field>
</record>
</odoo>