---
url: https://docs.cybrosys.com/assista-ide/odoo-standards/standards.md
description: >-
  Turn on optional warnings that check your Python and XML files against Odoo's
  coding guidelines while you edit.
---

# Odoo coding standards

Assista IDE can check your Python and XML files against Odoo's coding guidelines as you edit, so you catch naming and structure issues before a review. The warnings are off by default.

This feature comes from the bundled Odoo Helper. Read the guidelines themselves in the [Odoo documentation](https://www.odoo.com/documentation/master/contributing/development/coding_guidelines.html).

## What you can do

* **Catch naming issues** in models, fields, methods, record IDs and file names.
* **Keep files consistent** across your team, for example the import order and the order of attributes in XML.
* **See problems as you type**, as warnings in the editor and in the **Problems** panel. Each warning shows the rule that was broken and the pattern to use.

## Get started

1. Open **Settings**.
2. Search for **Enable Code Standard Warnings**.
3. Turn it on.

The checks run on `.py` and `.xml` files when you open them, as you type and when you save. Every finding is a warning on the line that triggered it. Turn the setting off to clear all warnings.

## What it checks

### Python

**Files and classes.** These checks run on files in a `models/` folder.

| Rule | Example |
| :--- | :--- |
| The file name is the snake_case form of the model class name. | `class CustomerInvoice` goes in `customer_invoice.py`, not `customerInvoice.py`. |
| Class names use CamelCase. | `class CustomerInvoice`, not `class customer_invoice`. |
| The `_name` of a model is singular. | `res.partner`, not `res.partners`. |
| The `_name` of a transient model follows `<base_model>.<action>`. | `account.invoice.import`. A name with no dot is flagged. |

**Fields**

| Rule | Example |
| :--- | :--- |
| `Many2one` field names end in `_id`. | `customer_id = fields.Many2one('res.partner')` |
| `One2many` and `Many2many` field names end in `_ids`. | `invoice_line_ids = fields.One2many(...)`, `category_ids = fields.Many2many(...)` |

**Methods**

| Rule | Example |
| :--- | :--- |
| Compute methods start with `_compute_`. | `_compute_total_amount` |
| Search methods start with `_search_`. | `_search_name` |
| Default methods start with `_default_`. | `_default_company_id` |
| Selection methods start with `_selection_`. | `_selection_state` |
| Onchange methods start with `_onchange_`. | `_onchange_customer_id` |
| Constraint methods start with `_check_`. | `_check_total_amount` |
| Action methods start with `action_`. | `action_validate` |
| `action_` methods call `self.ensure_one()` near the start. | `def action_validate(self): self.ensure_one()` |

A method is flagged when its name contains one of the keywords (`compute`, `search`, `default`, `selection`, `onchange`, `check` or `action`) but does not start with the matching prefix. `compute_total_amount` is flagged, and so is a core override such as `default_get`. You can ignore the warning on those overrides.

**Imports.** Order imports in three groups: the Python standard library, then `odoo`, then `odoo.addons`.

```python
import datetime
import logging

from odoo import api, fields, models
from odoo.addons.base.models import ir_model
```

**Patterns to avoid**

| Pattern | Use instead |
| :--- | :--- |
| `.clone()` | `dict(my_dict)` or `list(my_list)` |
| `cr.commit()` | Let Odoo commit. Commit yourself only on a cursor you created. |
| `_('Welcome %s' % name)`, formatting before translation | `_('Welcome %s', name)` |
| `_('Welcome ' + name)`, concatenation inside `_()` | One complete string literal. |
| `_('Welcome') % name`, formatting after translation | Put the values inside the `_()` call. |
| `_('Name: %s' % _(name))`, a nested `_()` | Leave field values untranslated. Odoo translates them. |
| `if len(records) > 0:` | `if records:` |
| `for key in my_dict.keys():` | `for key in my_dict:` |
| `my_dict.get('key', None)` | `my_dict.get('key')` |

> **Info.**
>
> The translation check flags any `%` inside `_()`, including the recommended `_('Welcome %s', name)`. If you follow the recommended form, you can ignore that warning.

### XML

**Elements and attributes**

| Rule | Example |
| :--- | :--- |
| On a `<record>`, put `id` before `model`. | `<record id="customer_invoice_view_form" model="ir.ui.view">` |
| On a `<field>`, put `name` first. | `<field name="invoice_number" type="char">` |
| Put `noupdate="1"` on `<odoo>`, not on `<data>`. | `<odoo noupdate="1">` |
| Use `<menuitem>`, not a record of `ir.ui.menu`. | `<menuitem id="customer_invoice_menu" .../>` |

**IDs.** A check applies to an ID when it contains the marker shown.

| Record | Pattern | Example |
| :--- | :--- | :--- |
| Menu, ID contains `_menu` | `<model>_menu` or `<model>_menu_<detail>` | `customer_invoice_menu_main` |
| View, any ID inside an `ir.ui.view` record | `<model>_view_<type>`, optionally ending in `_inherit`. The type is `form`, `list`, `kanban`, `search`, `calendar`, `graph`, `pivot`, `activity` or `tree`. | `customer_invoice_view_form` |
| Action, ID contains `_action` | `<model>_action` or `<model>_action_<detail>` | `customer_invoice_action` |
| Group, ID contains `_group_` | `<module>_group_<name>` | `invoice_group_manager` |
| Rule, ID contains `_rule_` | `<model>_rule_<group>` | `customer_invoice_rule_company` |

**View names.** In an `ir.ui.view` record, the `name` field uses dots and the form `<model.name>.view.<type>`, such as `customer.invoice.view.form`. For an inherited view, the name ends with `.inherit.<details>`, such as `customer.invoice.view.form.inherit.partner`.

### File names

The check uses the name of the folder that holds the file.

| Folder | Files must be named |
| :--- | :--- |
| `views/` (XML) | `*_views.xml`, `*_templates.xml` or `*_menus.xml` |
| `security/` (XML) | `*_groups.xml` or `*_security.xml` |
| `report/` (XML) | `*_report_views.xml`, `*_reports.xml` or `*_templates.xml` |
| `wizard/` (XML) | `*_views.xml` |
| `data/` (XML) | `*_data.xml` or `*_demo.xml` |
| `controllers/` (Python) | snake_case, such as `main.py` or `portal.py` |
| `wizard/` (Python) | snake_case |
| `report/` (Python) | `*_report.py` |

Access files (`ir.model.access.csv` and, on Odoo 20, `ir.access.csv`) are CSV files and are not checked.

## Tips and limits

* Warnings are suggestions based on Odoo's guidelines. You decide what to change.
* The checks only read `.py` and `.xml` files. They do not check CSV files.
* Turn the setting off again at any time if the warnings are noisy for an older project.
* Files that the [file and module generators](/assista-ide/module-creation) create can still trigger a few warnings, such as a placeholder view ID. Rename them as you fill in the template.

## Next steps

* Get [context-aware suggestions](/assista-ide/odoo-standards/code-suggestion).
* [Review a module](/assista-ide/features#review-a-module) with a full QA check.
