Se rendre au contenu

Attributs de modèles Odoo 19 : _order, _rec_name, Constraint

Bloc 3 · Framework ORM — Article 2/8 Attributs de modèles Odoo 19 : _order, _rec_name, Constraint Au-delà des trois classes de base, un modèle Odoo se…
26 avril 2026 par
Attributs de modèles Odoo 19 : _order, _rec_name, Constraint
B.Mustapha

Bloc 3 · Framework ORM — Article 2/8

Attributs de modèles Odoo 19 : _order, _rec_name, Constraint

Au-delà des trois classes de base, un modèle Odoo se configure via une dizaine d'attributs privés (préfixés _). On les passe en revue en enrichissant le module odooskills_helpdesk.

~14 minutes de lecture

Ce que tu vas apprendre

_order

Définir l'ordre de tri par défaut dans toutes les vues et recherches.

_rec_name

Choisir le champ affiché dans les Many2one et le breadcrumb.

Constraint

Poser des contraintes SQL (UNIQUE, CHECK) en syntaxe v19.

Autres

_inherit, _auto, _log_access, _table

Prérequis
  • Avoir lu l'article T08 — Modèles de base
  • Le module odooskills_helpdesk installé (on le fait évoluer ici)
  • Un environnement Odoo 19 fonctionnel
Le module fil rouge — Cet article fait passer odooskills_helpdesk de la version 19.0.1.0.0 à 19.0.1.1.0. On ajoute les attributs privés et une contrainte SQL d'unicité sur la référence du ticket.

Les attributs privés d'un modèle, en un coup d'œil

À gauche, la classe Python. À droite, ce que chaque attribut change concrètement dans Odoo.

Les attributs privés d'un modèle Odoo 19 _name, _description, _order, _rec_name, _inherit, _unique_* class HelpdeskTicket(models.Model): _name = 'helpdesk.ticket' _description = 'Ticket Helpdesk' _order = 'priority desc,' 'create_date desc' _rec_name = 'name' _inherit = ['mail.thread', 'mail.activity.mixin'] _unique_reference = models.Constraint( 'UNIQUE (reference)', "Doit être unique.") (puis viennent les fields...) Effet dans Odoo _name → crée la table helpdesk_ticket _description → libellé dans les menus/breadcrumb _order ORDER BY par défaut dans les    search() / vues list / kanban _rec_name → champ affiché dans les    Many2one et le breadcrumb _inherit → injecte les champs/méthodes    des mixins et classes parentes _unique_* → contrainte SQL UNIQUE en base    (remplace _sql_constraints v18) ⚠️ Odoo 19 : _sql_constraints et l'ancienne liste sont supprimés. Utiliser les models.Constraint via attribut de classe.

Les attributs privés Odoo commencent TOUS par un underscore _. Ils ne sont pas des champs : ils configurent le modèle.

1 — _order : trier par défaut

Par défaut, Odoo trie les enregistrements par id ascendant — autrement dit l'ordre d'insertion. C'est rarement ce qu'on veut. L'attribut _order redéfinit le tri utilisé par toutes les vues (list, kanban, search) et par tous les search() sans order= explicite.

Exemple — trier les tickets par priorité

Pour notre module helpdesk, on veut voir les tickets urgents en haut, puis par ordre chronologique inverse (plus récents en premier) :

class HelpdeskTicket(models.Model):
    _name = 'helpdesk.ticket'
    _description = 'Ticket Helpdesk'
    _inherit = ['mail.thread', 'mail.activity.mixin', 'odooskills.helpdesk.mixin']
    _order = 'priority desc, create_date desc'

La syntaxe est identique à SQL : liste de champs séparés par des virgules, avec asc (défaut) ou desc optionnel sur chacun.

Le champ doit être stocké — Tu ne peux pas utiliser un champ compute non stocké dans _order : l'ORM ne sait pas traduire ça en SQL. Ajoute store=True sur le champ calculé ou trie sur un autre champ.

2 — _rec_name : le champ "nom" du record

Chaque enregistrement Odoo a un nom affiché : c'est ce qui apparaît dans les Many2one (champ relation), dans le breadcrumb et dans la fonction display_name. Par défaut, Odoo cherche un champ name.

Si ton modèle n'a pas de champ name, il faut soit en créer un, soit pointer _rec_name sur un autre champ :

# Cas 1 : champ name standard — _rec_name est implicite
class HelpdeskTicket(models.Model):
    _name = 'helpdesk.ticket'
    _rec_name = 'name'  # par défaut — optionnel d'écrire cette ligne

    name = fields.Char(required=True)


# Cas 2 : pas de champ name, on pointe ailleurs
class HelpdeskTicketHistory(models.Model):
    _name = 'helpdesk.ticket.history'
    _rec_name = 'event_type'

    event_type = fields.Char(required=True)
    ticket_id = fields.Many2one('helpdesk.ticket')
Aller plus loin : display_name — Pour construire un nom combinant plusieurs champs (ex : "[TK-001] Panne imprimante"), surcharge la méthode _compute_display_name() plutôt que de jouer sur _rec_name. On verra le pattern dans l'article T12 (champs calculés).

3 — models.Constraint : les contraintes SQL en v19

Une contrainte SQL est une règle appliquée directement par PostgreSQL (unicité, valeur positive, date cohérente, etc.). Elle est beaucoup plus rapide et fiable qu'un @api.constrains Python car imposée en base, pas dans le code.

Syntaxe Odoo 19 — nouvelle et obligatoire

class HelpdeskTicket(models.Model):
    _name = 'helpdesk.ticket'

    # Contrainte unique — attribut de classe préfixé par _
    _unique_reference = models.Constraint(
        'UNIQUE (reference)',
        "La référence du ticket doit être unique.",
    )

    # Contrainte CHECK : valeur autorisée
    _priority_check = models.Constraint(
        "CHECK (priority IN ('0', '1', '2'))",
        "Priorité invalide.",
    )

    reference = fields.Char(copy=False, index=True)
    priority = fields.Selection([('0', 'Normale'), ('1', 'Haute'), ('2', 'Urgente')])
⚠️ Ce qui a disparu en Odoo 19

L'ancienne syntaxe _sql_constraints sous forme de liste de tuples est totalement supprimée :

# ❌ Odoo 18 et avant — ne fonctionne PLUS en v19
_sql_constraints = [
    ('reference_unique', 'UNIQUE (reference)', "Doit être unique."),
]

# ❌ Même les nouvelles listes avec models.Constraint(...) sont supprimées
_constraints = [models.Constraint(...)]  # erreur à l'install

# ✅ Odoo 19 — uniquement des attributs de classe séparés
_unique_reference = models.Constraint('UNIQUE (reference)', "Doit être unique.")

Vérification en base

Après un -u odooskills_helpdesk, PostgreSQL montre la contrainte :

psql -d odooskills_helpdesk_test -c "\d helpdesk_ticket" | grep -i unique
"helpdesk_ticket_unique_reference" UNIQUE CONSTRAINT, btree (reference)

Le nom de la contrainte en base est <table>_<nom_attribut> — ici helpdesk_ticket_unique_reference. Odoo applique cette convention automatiquement.

4 — _inherit : hériter de modèles existants

On l'a utilisé sans l'expliquer dans T08. _inherit prend une liste de modèles dont on veut hériter les champs et méthodes. Il existe trois cas d'usage :

Cas Syntaxe Effet
Extension classique _inherit = 'res.partner' (sans _name) Ajoute des champs au modèle existant
Prototypage (delegation) _inherits = {'res.partner': 'partner_id'} Nouveau modèle qui délègue à un autre via Many2one
Mixin _inherit = ['mail.thread', 'mixin.name'] Injecte les champs/méthodes des mixins

Dans notre module, on utilise la forme mixin pour ajouter le chatter, les activités et les champs communs via notre AbstractModel :

class HelpdeskTicket(models.Model):
    _name = 'helpdesk.ticket'
    _inherit = [
        'mail.thread',                      # chatter + messages
        'mail.activity.mixin',              # activités planifiées
        'odooskills.helpdesk.mixin',        # notre mixin custom (active, priority)
    ]

L'article T13 couvrira l'héritage en profondeur (extension de modèles existants, prototypage). Ici, retenir juste la forme mixin.

5 — Les autres attributs à connaître

Attribut Valeur par défaut À quoi ça sert
_table Déduit de _name Nom de table PostgreSQL custom (rarement changé)
_auto True Créer automatiquement la table. False = tu la crées toi-même (vue SQL, table existante)
_log_access True Ajouter create_uid, create_date, write_uid, write_date
_abstract False Déclarer un modèle abstrait (mais préfère AbstractModel directement)
_check_company_auto False Vérifier automatiquement la cohérence de company_id entre records liés
_parent_name 'parent_id' Nom du champ Many2one self-reference pour les hiérarchies
_parent_store False Activer l'index MPTT pour parcourir les hiérarchies efficacement

Ces attributs sont à connaître mais rarement à modifier. Les cas _parent_* sont couverts dans l'article T14 (hiérarchie).

6 — Mettre à jour le module helpdesk

On applique tous ces attributs à nos deux modèles persistants. Voici les fichiers mis à jour :

models/helpdesk_ticket.py

from odoo import models, fields


class HelpdeskTicket(models.Model):
    _name = 'helpdesk.ticket'
    _description = 'Ticket Helpdesk'
    _inherit = ['mail.thread', 'mail.activity.mixin', 'odooskills.helpdesk.mixin']
    _order = 'priority desc, create_date desc'
    _rec_name = 'name'

    _unique_reference = models.Constraint(
        'UNIQUE (reference)',
        "La référence du ticket doit être unique.",
    )

    name = fields.Char(string='Sujet', required=True, tracking=True)
    reference = fields.Char(string='Référence', copy=False, index=True)
    description = fields.Text(string='Description')
    # ... autres champs inchangés

models/helpdesk_ticket_category.py

from odoo import models, fields


class HelpdeskTicketCategory(models.Model):
    _name = 'helpdesk.ticket.category'
    _description = 'Catégorie de ticket helpdesk'
    _order = 'sequence, name'
    _rec_name = 'name'

    _unique_name = models.Constraint(
        'UNIQUE (name)',
        "Le nom de la catégorie doit être unique.",
    )

    name = fields.Char(string='Nom', required=True)
    sequence = fields.Integer(string='Séquence', default=10)
    color = fields.Integer(string='Couleur')

__manifest__.py

On incrémente la version pour signaler l'évolution :

{
    'name': 'OdooSkills Helpdesk',
    'version': '19.0.1.1.0',    # 1.0.0 → 1.1.0 : attributs + contrainte
    # ... reste inchangé
}

Lancer la mise à jour

./odoo-bin -c config/odoo.conf -d odooskills_helpdesk_test \
    -u odooskills_helpdesk --stop-after-init

Puis vérifier les contraintes et le champ reference en base :

psql -d odooskills_helpdesk_test -c "\d helpdesk_ticket" | grep -iE 'reference|unique'
 reference   | character varying |           |          |
   "helpdesk_ticket__reference_index" btree (reference)
   "helpdesk_ticket_unique_reference" UNIQUE CONSTRAINT, btree (reference)

Récapitulatif

Attribut Rôle À mettre quand ?
_nameIdentifiant techniqueToujours
_descriptionLibellé humainToujours (linter Odoo)
_orderTri par défautDès que l'ordre naturel par ID ne convient pas
_rec_nameChamp "nom" affichéSi pas de champ name
_inheritHéritage / mixinsPresque toujours (mail.thread, activity…)
_unique_*Contrainte UNIQUE SQLPour garantir l'unicité en base

Pour aller plus loin

  • Article suivant (T10) — Les champs non-relationnels : Char, Text, Integer, Float, Boolean, Date, Selection, Html, Binary. On ajoute 12 champs au ticket helpdesk
  • Article T12 — Contraintes Python (@api.constrains) quand la règle ne peut pas s'exprimer en SQL
  • Ressources officielles :

Télécharge le Guide Technique Odoo 19

Architecture, pièges v19, checklist premier module — tout dans un PDF gratuit.

Télécharger le guide
Modèles de base Odoo 19 : Model, TransientModel, AbstractModel
Bloc 3 · Framework ORM — Article 1/8 Modèles de base Odoo 19 : Model, TransientModel, AbstractModel Tout module Odoo repose sur des modèles Python.