Champs de calcul
Les relations entre les modèles sont un élément clé de tout module Odoo. Elles sont nécessaires à la modélisation de toute affaire. Cependant, nous pouvons vouloir des liens entre les champs d’un modèle donné. Parfois, la valeur d’un champ est déterminée à partir des valeurs d’autres champs, nous voulons aider l’utilisateur à saisir des données.
Ces cas sont pris en charge par les concepts de champs calculés et de modifications (onchanges). Bien que ce chapitre ne soit pas techniquement complexe, la sémantique de ces deux concepts est très importante. C’est également la première fois que nous écrivons de la logique Python. Jusqu’à présent, nous n’avons rien écrit d’autre que des définitions de classes et des déclarations de champs.
Champs calculés
Objectif : à la fin de cette section :
Dans le modèle immobilier, la surface totale et la meilleure offre doivent être calculées :
- Dans le modèle d’offre de biens immobiliers, la date de validité doit être calculée et peut être mise à jour :
Dans un module immobilier, nous avons défini la surface habitable ainsi que la surface du jardin. Il est donc naturel de définir la surface totale comme la somme des deux champs. Pour ce faire, nous utiliserons le concept de champ calculé, c’est-à-dire que la valeur d’un champ donné sera calculée à partir de la valeur d’autres champs.
Jusqu’à présent, les champs ont été stockés directement dans la base de données et extraits directement de celle-ci. Les champs peuvent également être calculés. Dans ce cas, la valeur du champ n’est pas extraite de la base de données mais calculée à la volée en appelant une méthode du modèle.
Pour créer un champ calculé, créez un champ et lui affectez un attribut compute le nom d’une méthode. La méthode de calcul doit définir la valeur du champ calculé pour chaque enregistrement de self.
Par convention, les méthodes de calcul sont privées, ce qui signifie qu’elles ne peuvent pas être appelées depuis le niveau de présentation, mais uniquement depuis le niveau métier (voir le chapitre 1 : Présentation de l’architecture). Les méthodes privées ont un nom commençant par un trait de soulignement _.
Dépendances
La valeur d’un champ calculé dépend généralement des valeurs d’autres champs de l’enregistrement calculé. L’ORM attend du développeur qu’il spécifie ces dépendances sur la méthode de calcul avec le décorateur depends(). Les dépendances données sont utilisées par l’ORM pour déclencher le recalcul du champ lorsque certaines de ses dépendances ont été modifiées :
from odoo import api, fields, models class TestComputed(models.Model): _name = "test.computed" total = fields.Float(compute="_compute_total") amount = fields.Float() @api.depends("amount") def _compute_total(self): for record in self: record.total = 2.0 * record.amount
Remarque
self est une collection.
L’objet self est un jeu d’enregistrements, c’est-à-dire une collection ordonnée d’enregistrements. Il supporte les opérations standard de Python sur les collections, par exemple len(self) et iter(self), ainsi que des opérations supplémentaires sur les ensembles telles que recs1 | recs2.
L’itération sur self permet d’obtenir les enregistrements un par un, chaque enregistrement étant lui-même une collection de taille 1. Vous pouvez accéder/assigner des champs sur des enregistrements individuels en utilisant la notation point, par exemple record.name.
Activité : créer un champ calculé
Dans cet exercice, nous allons créer un champ calculé appelé « capitalized_name » dans le modèle HospitalPatient
du fichier patient.py
. Ce champ utilisera une fonction de calcul _compute_capitalized_name
pour convertir le nom en minuscules en majuscules. Voici les étapes à suivre :
- Ouvrez le fichier
patient.py
qui définit le modèleHospitalPatient
. - Ajoutez l’importation du module
fields
dans la liste des importations en haut du fichier :
from odoo import models, fields
- Dans la classe
HospitalPatient
, ajoutez le champ calculé « capitalized_name » et la fonction de calcul_compute_capitalized_name
:
class HospitalPatient(models.Model):
_name = 'hospital.patient'
_description = "Patient Records"
name = fields.Char(string='Name', required=True)
capitalized_name = fields.Char(string='Capitalized Name', compute='_compute_capitalized_name')
@api.depends('name')
def _compute_capitalized_name(self):
for rec in self:
if self.name:
self.capitalized_name = patient.name.upper()
else:
self.capitalized_name = ''
- Enregistrez vos modifications dans le fichier
patient.py
. - Redémarrez votre serveur Odoo pour appliquer les modifications.
Maintenant, lorsque vous créez ou modifiez un patient et saisissez un nom, le champ calculé « capitalized_name » sera automatiquement mis à jour à l’aide de la fonction _compute_capitalized_name
. Cette fonction convertit le nom en minuscules en majuscules à l’aide de la méthode upper()
de Python.
Cela permet d’afficher automatiquement le nom en majuscules dans le champ « Capitalized Name » du formulaire du patient. Si aucun nom n’est saisi, le champ sera vide.
Cet exercice démontre l’utilisation des champs calculés et des fonctions de calcul pour effectuer des opérations sur les données du modèle et les afficher de manière transformée dans l’interface utilisateur.
Rendre la fonction capable de gérer plusieurs enregistrements
La boucle for rec in self:
est utilisée dans Odoo pour itérer sur un ensemble d’enregistrements d’un modèle. Dans le contexte d’une méthode de modèle, self
fait référence à l’ensemble des enregistrements actuellement traités.
Lorsque vous utilisez for rec in self:
, vous parcourez chaque enregistrement individuellement et pouvez effectuer des opérations sur chacun d’entre eux. L’objet rec
représente un enregistrement spécifique dans l’ensemble.
Voici un exemple d’utilisation de la boucle for rec in self:
:
class HospitalPatient(models.Model):
_name = 'hospital.patient'
_description = "Patient Records"
name = fields.Char(string='Name', required=True)
age = fields.Integer(string='Age')
def print_patient_details(self):
for rec in self:
print(f"Patient Name: {rec.name}")
print(f"Patient Age: {rec.age}")
Dans cet exemple, la méthode print_patient_details
est définie dans le modèle HospitalPatient
. Lorsqu’elle est appelée, la boucle for rec in self:
itère sur chaque enregistrement de self
, c’est-à-dire tous les patients. À chaque itération, les détails du patient sont affichés à l’aide de rec.name
et rec.age
.
La boucle for rec in self:
est un moyen pratique de travailler avec plusieurs enregistrements dans Odoo. Vous pouvez effectuer des opérations spécifiques sur chaque enregistrement individuel en utilisant l’objet rec
. Cela permet de traiter les données de manière itérative et d’effectuer des opérations en fonction des caractéristiques de chaque enregistrement.
Rendre le champ de calcul stocké
Activité : Rendre le champ de calcul stocké
Pour rendre le champ de calcul stocké, vous pouvez utiliser un champ persistant tel que fields.Char
ou fields.Text
. Voici comment modifier l’exercice précédent pour rendre le champ « capitalized_name » stocké :
- Ouvrez à nouveau le fichier
patient.py
qui définit le modèleHospitalPatient
. - Modifiez la définition du champ « capitalized_name » en utilisant un champ persistant :
capitalized_name = fields.Char(string='Capitalized Name', compute='_compute_capitalized_name', store=True)
- Enregistrez vos modifications dans le fichier
patient.py
.
Maintenant, lorsque vous créez ou modifiez un patient et saisissez un nom, le champ « capitalized_name » sera automatiquement mis à jour et stocké dans la base de données. Cela signifie que la valeur calculée sera conservée même après la fermeture et la réouverture de l’application.
Il est important de noter que l’utilisation de store=True
peut augmenter la taille de la base de données car les valeurs calculées sont stockées. Assurez-vous de prendre en compte les performances et l’espace de stockage nécessaires avant de décider de rendre un champ calculé stocké.