The ORM (models & fields)

Models are Python classes mapped to database tables. The ORM is how you define data and business logic.

Define a model

from odoo import api, fields, models

class Lead(models.Model):
    _name = "my.lead"
    _description = "Lead"

    name = fields.Char(required=True)
    partner_id = fields.Many2one("res.partner", string="Customer")
    expected = fields.Float()
    stage = fields.Selection(
        [("new", "New"), ("won", "Won"), ("lost", "Lost")],
        default="new",
    )

Field types

Char, Text, Boolean, Integer, Float, Monetary, Date, Datetime, Selection, Binary, and relational fields Many2one, One2many, Many2many.

Computed fields

total = fields.Float(compute="_compute_total", store=True)

@api.depends("expected")
def _compute_total(self):
    for rec in self:
        rec.total = rec.expected * 1.2

Working with records

self.env["my.lead"].create({"name": "Acme"})
leads = self.env["my.lead"].search([("stage", "=", "new")])
leads.write({"stage": "won"})
count = self.env["my.lead"].search_count([])

Version 19 notes

These changed from older releases — use the current form:

  • Constraints: define SQL constraints with models.Constraint, not the deprecated _sql_constraints list.
  • Groups on records: the field is group_ids (not groups_id); users are user_ids (not users) on res.groups.
  • Group categories: use privilege_id with the res.groups.privilege model.
  • Optional Python dependencies: a module that lists an external Python package blocks install if the package is missing — import such packages lazily inside methods rather than at module top level.
  • Show your model on screen — Views.
  • Lock it down — Security.

Need a hand with this? company@everjust.co — a human answers.