Skip to content

OD118 create-reads-dict

create() under @api.model reads its argument as one dict, but receives a list of them.

Category Severity Series Needs the index
Correctness Error saas~18.2 and later no

What it reports

A create method of a model class decorated with @api.model whose body reads the argument after self as one dict: by a string key, with get, items, keys, values, setdefault, update or pop given a string, with a string in test, or unpacked with **. The finding is at the decorator.

A body that rebinds the argument, or tests it with isinstance, may handle a list as well, so it is not reported, and neither is a read in a nested function or a lambda, which may name a parameter of its own alike.

Why it matters

From saas~18.2, so in 19.0, @api.model on create is @api.model_create_multi: Odoo wraps a single dict in a list before it calls the method, so the method always receives a list of dicts. Reading it as one dict then fails on the first record created: vals["name"] raises TypeError, vals.get("name") raises AttributeError, and "name" in vals is always false, so the code it guards never runs. Loop over the list, and say what the method takes with @api.model_create_multi.

Before saas~18.2, Odoo calls such a method once per dict instead, which OD117 reports from saas~15.2.

Example

models/res_partner.py
class ResPartner(models.Model):
    _inherit = "res.partner"

    @api.model
    def create(self, vals):
        vals.setdefault("comment", "Imported")
        return super().create(vals)
models/res_partner.py
class ResPartner(models.Model):
    _inherit = "res.partner"

    @api.model_create_multi
    def create(self, vals_list):
        for vals in vals_list:
            vals.setdefault("comment", "Imported")
        return super().create(vals_list)

Suppressing

@api.model  # odooscan: ignore[OD118]

See suppressing a finding.