Chapitre 6 : Création d’un module sur Odoo (part 13)

Décorateur de contraintes dans Odoo

Le chapitre précédent a introduit la possibilité d’ajouter de la logique métier à notre modèle. Nous pouvons maintenant lier les boutons au code métier, mais comment empêcher les utilisateurs de saisir des données incorrectes ? Par exemple, dans notre module immobilier, rien n’empêche les utilisateurs de définir un prix attendu négatif.

Odoo propose deux façons de mettre en place des invariants vérifiés automatiquement : Les contraintes Python et les contraintes SQL

SQL

Remarque

Objectif : à la fin de cette section :

Les montants doivent être (strictement) positifs

Constraints on amounts

  • Les types de propriété et les étiquettes doivent avoir un nom unique

Constraints on names

Les contraintes SQL sont définies par l’attribut de modèle _sql_constraints. Cet attribut se voit attribuer une liste de triplets contenant des chaînes (name, sql_definition, message), où name est un nom de contrainte SQL valide, sql_definition est une expression de contrainte de table et message est le message d’erreur.

Python

Remarque

Objectif : à la fin de cette section, il ne sera pas possible d’accepter une offre inférieure à 90% du prix prévu.

Python constraint

Les contraintes SQL sont un moyen efficace de garantir la cohérence des données. Cependant, il peut être nécessaire d’effectuer des vérifications plus complexes qui requièrent du code Python. Dans ce cas, nous avons besoin d’une contrainte Python.

Une contrainte Python est définie comme une méthode décorée avec constrains() et est invoquée sur un jeu d’enregistrements. Le décorateur spécifie les champs concernés par la contrainte. La contrainte est automatiquement évaluée lorsque l’un de ces champs est modifié. La méthode est censée lever une exception si son invariant n’est pas satisfait :

from odoo.exceptions import ValidationError

...

@api.constrains('date_end')
def _check_date_end(self):
    for record in self:
        if record.date_end < fields.Date.today():
            raise ValidationError("The end date cannot be set in the past")
    # all records passed the test, don't return anything

Activité : Créer une contrainte

  1. Ouvrez le fichier contenant le modèle Patient (patient.py) dans votre éditeur de code.
  2. Ajoutez l’import from odoo.exceptions import ValidationError au début du fichier.
  3. Recherchez la classe HospitalPatient qui définit le modèle Patient.
  4. Ajoutez la méthode _check_age_is_zero() avec l’annotation @api.constrains('age', 'is_child') dans la classe HospitalPatient.
  5. À l’intérieur de la méthode _check_age_is_zero(), utilisez une boucle for rec in self pour parcourir les enregistrements concernés.
  6. À l’intérieur de la boucle, ajoutez une condition pour vérifier si rec.age est égal à 0 et que rec.is_child est activé.
  7. Si les conditions sont remplies, utilisez raise ValidationError("Invalid combination: Age cannot be 0 if Is Child is enabled.") pour générer une exception ValidationError avec un message d’erreur approprié.
  8. Enregistrez le fichier.

Exemple de code :

from odoo import models, fields, api
from odoo.exceptions import ValidationError

class HospitalPatient(models.Model):
    ..................................

    @api.constrains('age', 'is_child')
    def _check_age_is_zero(self):
        for rec in self:
            if rec.age == 0 and rec.is_child:
                raise ValidationError("Invalid combination: Age cannot be 0 if Is Child is enabled.")
          ............................

Dans cet exercice, vous devez ajouter une contrainte qui vérifie si l’âge est égal à 0 et que is_child est activé. Si ces conditions sont satisfaites, une exception sera générée, empêchant la validation de l’enregistrement. Assurez-vous de recharger le module Odoo après avoir effectué ces modifications pour que la contrainte prenne effet.