OD116 field-shadows-model-member¶
A field is named like a method or an attribute every model has.
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Correctness | Error | all | no |
What it reports¶
A field of a model class named like a method of BaseModel that the ORM or its callers use, such
as copy, write, search or name_search, like the record attributes env, ids and pool,
or the class attribute _table_query, the SQL query a model reads its records from. The finding is
at the field's name.
Why it matters¶
A field is a class attribute of the model, so Python finds it before the method or attribute of
the same name that every model inherits from BaseModel. Odoo never checks for it: the model
loads, and then record.copy() gets the field's value instead of the method, as does the ORM
itself and every RPC call of the method. A field named env breaks every recordset of the model,
since building one assigns its env. Rename the field, and give it the label the old name gave if
users know it by that.
The list of methods is that of the ORM API reference, with the methods Odoo's own addons override.
A name that is not in it is not reported, so a field named like a less common BaseModel method
goes unnoticed. A member only some series have counts in those series: check_access and
has_access from 18.0, the methods 20.0 adds from 20.0, and those 20.0 drops, such as
toggle_active and check_access_rights, up to 18.0. The attribute _table_query counts from
saas~13.5 up to the last release before 20.0, and the method _condition_to_sql, which moved to
Field, from saas~17.1 to saas~18.3. _read, _name_search and copy_multi, which neither has,
never count.
A module of unknown series is checked only against the methods that count in every series. Those
are the methods 18.0 and 20.0 both have, since the series that added each one is not known: a
field named grouped, fetch or search_fetch is reported in every series, even one whose
BaseModel lacks the method.
Example¶
class ParcelBox(models.Model):
_name = "parcel.box"
_description = "Parcel box"
copy = fields.Boolean()
class ParcelBox(models.Model):
_name = "parcel.box"
_description = "Parcel box"
is_copy = fields.Boolean(string="Copy")