development:odoo_dev_intro

Odoo, framework de développement web

Odoo peut être utilisé comme un framework de développement web tout comme Django ou Flask.

Odoo se différencie de ces frameworks par le fait qu'il embarque à la base des modules orientés entreprise sous forme d'applications prêtes à l'installation.

Nous allons faire abstraction de ces modules pour nous concentrer sur Odoo en tant que framework de développement web en espérant que cela aidera à la prise en main de cette application par les développeurs.

Odoo est une application implémentée dans le langage python qui est un langage interprété (cet aspect a un impact sur le workflow de développement comme nous le verrons plus tard).

Au démarrage, Odoo a besoin d'être préconfiguré pour se connecter au gestionnaire de base de données Postgresql.

Odoo a également besoin d'être instruit des chemins (paths) où il trouvera les modules complémentaires que les développeurs ajouteront pour enrichir l'application.

Ces détails sont déjà pris en charge dans l'environnement de développement qui vous est livré à votre entrée à Elosys.

Pour favoriser un enrôlement rapide des stagiaires et des nouvelles recrues, un environnement de développement est mis à leur disposition en partie avec le dépôt https://git.elosys.net/sys/dotfiles.

Cet environnement comprend des aliases et des fonctions bash, une configuration tmux ainsi que des dispositifs docker et docker-compose.

Elosys vous fournira un dispositif minimal mais complet qui vous permettra de démarrer rapidement avec Odoo grâce à docker.

Un dossier contenant deux fichiers docker-compose.yml et odoo.conf vous suffira pour commencer.

$ cd service.odoo
$ ll
total 20K
-rw-r--r--  1 user             user  683 juin  15 15:22 docker-compose.yml
-rw-r--r--  1 user             user 1,2K juin  15 15:21 odoo.conf
$ dcu

La commande dcu lancera deux containers listés dans le fichier docker-compose.yml.

Lors de ce premier lancement, vous devez attendre que le gestionnaire de base de données Postgresql initialise son cluster 1) . Cela devrait être indiqué par un message de type :

odoo_db | PostgreSQL init process complete; ready for start up.
odoo_db |
odoo_db | 2022-06-15 14:23:28.769 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
odoo_db | 2022-06-15 14:23:28.769 UTC [1] LOG:  listening on IPv6 address "::", port 5432
odoo_db | 2022-06-15 14:23:28.852 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
odoo_db | 2022-06-15 14:23:29.005 UTC [67] LOG:  database system was shut down at 2022-06-15 14:23:28 UTC
odoo_db | 2022-06-15 14:23:29.059 UTC [1] LOG:  database system is ready to accept connections

Une fois le cluster de base de données initialisé, arrêtez les containers en tapant Ctrl + c.

Le dossier qui ne contenait jusque là que deux fichiers docker-compose.yml et odoo.conf contiendra trois dossiers supplémentaires :

$ ll
total 20K
drwx------ 19 systemd-coredump root 4,0K juin  15 15:27 data
drwxr-xr-x  2 root             root 4,0K juin  15 15:23 extra-addons
drwxr-xr-x  2 root             root 4,0K juin  15 15:23 filestore
-rw-r--r--  1 user             user  683 juin  15 15:22 docker-compose.yml
-rw-r--r--  1 user             user 1,2K juin  15 15:21 odoo.conf
$

Vu que les dossiers spécifiques à Odoo extra-addons et filestore n'ont pas les bonnes autorisations, nous devrons lancer la commande ff pour régler le problème 2)

$ ff
$ ll
total 20K
drwx------ 19 systemd-coredump root            4,0K juin  15 15:27 data
drwxr-xr-x  2 user             user            4,0K juin  15 15:23 extra-addons
drwxr-xr-x  2 systemd-timesync systemd-journal 4,0K juin  15 15:23 filestore
-rw-r--r--  1 user             user             683 juin  15 15:22 docker-compose.yml
-rw-r--r--  1 user             user            1,2K juin  15 15:21 odoo.conf
$

A partir de maintenant l'environnement est prêt à recevoir vos développements.

dcu et dcd sont les deux commandes utilisées pour, respectivement, démarrer et arrêter les containers Odoo et Postgresql.

Nous avons auparavant vu l'usage du raccourci Ctrl + c pour arrêter les deux containers (Odoo et Postgresql) en cours d'exécution sur le même terminal.

Les commandes dcd et dcu dépendent du fichier docker-compose.yml. Elle doivent donc être exécutées à partir d'un dossier contenant le fichier docker-compose.yml ou dans un sous-dossier de ce dossier.

Il est généralement pas nécessaire d'arrêter le container Postgresql. Ce qui nous importe le plush dans notre workflow de développement c'est de redémarrer l'application Odoo.

Cette tâche peut être effectuée de manière sélective en utilisant la commande :

$ docker-compose restart odoo

La commande ci-dessus ne fera qu'arrêter puis démarrer l'application Odoo. Comme les commandes dcu et dcd cette commande doit être exécutée dans un dossier qui contient le fichier docker-compose.yml ou dans un sous-dossier de ce dossier.

Comme nous l'avons évoqué auparavant la nature interprétée du langage python impose un certain workflow de développement que nous allons poser ici et que nous rappelleront au cours de cette introduction :

Si vous modifiez un fichier python au cours de votre développement vous devez à minima3) redémarrer l'application Odoo pour que vos modifications soient chargées dans le nouvel interpréteur qui portera l'application Odoo.

Après avoir démarré Odoo avec dcu, rendez-vous avec votre navigateur sur l'adresse http://127.0.0.1:8069/. Vous serez invité à créer votre première base de données.

Durant cette initialisation, observez le log de l'application sur votre terminal. Le log vous renseignera sur la procédure d'initialisation d'une installation Odoo de base. 4)

A la fin de l'initialisation de la base de données, vous serez redirigé vers la page d'accueil de l'application Odoo. 5)

Qu'est ce qu'un module Odoo ?

Un module Odoo est d'abord un paquet python.

Un paquet python est un dossier dans lequel réside un fichier nommé __init__.py.

Un module Odoo est un paquet python dans lequel réside un fichier supplémentaire nommé __manifest__.py.

En somme, un module Odoo est un dossier dans lequel on trouve deux fichiers __init__.py et __manifest__.py.

Si le fichier __init__.py peut être vide, le fichier __manifest__.py doit contenir un dictionnaire qui contient au moins une valeur texte pour la clé name. 6) Comme ceci :

__manifest__.py
{
   'name': 'Mon module',
}

Reste à répondre à la question : où doit-on créer ces fichiers ?

Dans le dossier extra-addons.

Dans la suite de commandes suivante nous allons :

  • créer un dossier monmodule dans le dossier extra-addons
  • créer les fichiers __init__.py et __manifest__.py dans le dossier monmodule
  • remplir le fichier __manifest__.py avec le dictionnaire minimal requis.

Nous allons enfin, démarrer ou redémarrer l'application Odoo.

$ ll
total 20K
drwx------ 19 systemd-coredump root            4,0K juin  15 15:27 data
drwxr-xr-x  2 user             user            4,0K juin  15 15:23 extra-addons
drwxr-xr-x  2 systemd-timesync systemd-journal 4,0K juin  15 15:23 filestore
-rw-r--r--  1 user             user             683 juin  15 15:22 docker-compose.yml
-rw-r--r--  1 user             user            1,2K juin  15 15:21 odoo.conf
$ cd extra-addons
$ mkdir monmodule
$ cd monmodule
$ touch __init__.py
$ touch __manifest__.py
$ echo "{'name':'Mon Module',}" | tee __manifest__.py
$ docker-compose down && docker-compose up -d

En se loggant sur l'application, la page d'accueil par défaut sur laquelle nous atterrissons est la vue consacrées aux applications disponibles.

Nous pouvons filtrer 7) pour n'afficher que les modules qui correspondent au module minimal que nous venons de créer.

Après avoir éliminé le filtre App nous pouvons filtrer en écrivant Mon module ou monmodule dans la barre de recherche. Ci-dessous le résultat qui devrait s'afficher.

Nous avons vu dans ce qui a précédé :

  • Comment initialiser une installation Odoo avec docker.
  • Comment créer un module Odoo minimal.

Qu'est-ce qu'un modèle ?

Un modèle est une table dans la base de données.

Une des propriétés des frameworks de développement tels que Odoo est la possibilité de représenter et de manipuler la base de données sous une forme orientée objet. Ce dispositif implémenté dans Odoo s'appelle ORM et nous allons l'explorer dans ce qui suit pour créer et définir des tables dans la base de données Postgresql.

Nous créons notre premier modèle dans un nouveau fichier python.

$ cd ~/service.odoo/extra-addons/monmodule
$ touch models.py
$ editor models.py

Le fichier models.py contiendra le strict minimum pour créer un model dans la base de données.

models.py
from odoo import models
 
class Professeur(models.Model):
    _name = 'elo.prof'

Pour créer un modèle nous utilisons une classe qui hérite de la classe models.Model.

Le nom de la table dans la base de données (model name) est défini par la valeur de l'attribut spécial _name.

Pour que le nouveau fichier models.py soit chargé et évalué par l'interpréteur Python, nous devons le répertorier dans le fichier __init__.py du module, comme suit :

$ cd ~/service.odoo/extra-addons/monmodule
$ echo "from . import models"   | tee -a __init__.py
$ cat __init__.py
from . import models
$

Vu que nous avons édité des fichiers python dans notre module (__init__.py et ajouté un nouveau fichier models.py), nous devons redémarrer Odoo pour que ces modifications soient chargées par l'interpréteur qui embarque l'application Odoo.

Après le redémarrage d'Odoo, nous nous rendons à la vue App et nous filtrons sur notre application monmodule comme indiqué ici monmodule.png.

Il ne reste qu'à appuyer sur le boutton Install.

Voici ce que nous pouvons lire dans le log de l'application après avoir appuyé sur le bouton.

01 odoo  | ..... 1 INFO base odoo.addons.base.models.ir_module: ALLOW access to module.button_immediate_install on ['monmodule'] to user admin #2 via 172.17.0.1
02 odoo  | ..... 1 INFO base odoo.addons.base.models.ir_module: User #2 triggered module installation
03 odoo  | ..... 1 INFO base odoo.addons.base.models.ir_module: ALLOW access to module.button_install on ['monmodule'] to user admin #2 via 172.17.0.1
04 odoo  | ..... 1 INFO base odoo.modules.loading: loading 1 modules...
05 odoo  | ..... 1 INFO base odoo.modules.loading: 1 modules loaded in 0.03s, 0 queries (+0 extra)
06 odoo  | ..... 1 INFO base odoo.modules.loading: updating modules list
07 odoo  | ..... 1 INFO base odoo.addons.base.models.ir_module: ALLOW access to module.update_list on [] to user __system__ #1 via 172.17.0.1
08 odoo  | ..... 1 INFO ? werkzeug: 172.17.0.1 - - [05/Jul/2022 11:18:12] "GET /web/static/src/img/spin.png HTTP/1.1" 200 - - - -
09 odoo  | ..... 1 INFO base odoo.modules.loading: loading 8 modules...
10 odoo  | ..... 1 INFO base odoo.modules.loading: 8 modules loaded in 0.03s, 0 queries (+0 extra)
11 odoo  | ..... 1 INFO base odoo.modules.loading: loading 9 modules...
12 odoo  | ..... 1 INFO base odoo.modules.loading: Loading module monmodule (2/9)
13 odoo  | ..... 1 WARNING base odoo.models: The model elo.prof has no _description
14 odoo  | ..... 1 INFO base odoo.modules.registry: module monmodule: creating or updating database tables
15 odoo  | ..... 1 INFO base odoo.modules.loading: Module monmodule loaded in 1.43s, 35 queries
16 odoo  | ..... 1 INFO base odoo.modules.loading: 9 modules loaded in 1.43s, 35 queries (+0 extra)
17 odoo  | ..... 1 WARNING base odoo.modules.loading: The model elo.prof has no access rules, consider adding one. E.g. access_elo_prof,access_elo_prof,model_elo_prof,base.group_user,1,0,0,0
  • À la ligne 01 l'application nous informe que la pression sur le bouton Install a bien été enregistrée et appelle la méthode correspondante module.button_immediate_install.
  • À la ligne 12 l'application nous informe que Odoo charge notre module Loading module monmodule
  • À la ligne 13 l'application émet un WARNING sur l'absence de l'attribut _description pour le model elo.prof que nous nous apprêtons à créer grâce aux instructions du fichiers models.py de notre module.
  • À la ligne 14 l'application nous informe qu'elle est sur le point de créer les tables de base de données
  • Enfin, à la dernière ligne l'application émet un WARNING sur l'absence de règles d'accès sur la tables elo.prof que nous venons de créer. 8)

Comment vérifier que notre modèle a bien été crée par Odoo dans la base de données ?

Même si cette page de référence du site Odoo présente plusieurs façons d'activer le mode développeur dans l'interface web de Odoo, nous vous recommandons d'installer l'extension Odoo Debug disponible pour Firefox et pour Chrome

En activant le mode développeur, vous avez accès à des menus et des fonctionnalités supplémentaires qui vous aideront à mieux introspecter votre installation Odoo.

Ci-dessous, vous verrez des menus supplémentaire sur la vue App à l'activation du mode debug.

Une étude extensive de l'usage du debug mode est abordée sur un autre support. TODO

Dans le menu Settings appuyer sur Technical et scroller jusqu'à la section Database Structure et sélectionner Models.

Les modèles installés dans votre base de données sont eux-mêmes répertoriés dans un modèle spécifique du nom de ir.model.

Dans cette vue sur les enregistrements du model ir.model, nous avons donc l'intégralité des tables existantes dans notre installation Odoo.

Nous pouvons filtrer pour chercher la table que nous avons créée dans notre fichier models.py en inscrivant elo dans la zone de recherche.

Notre table elo.prof devrait apparaître comme dans la capture suivante.

En sélectionnant cet enregistrement, nous en aurons donc une vue détaillée que nous appelons vue formulaire (ou form view en anglais).

Dans cette vue nous pouvons déjà voir les champs qui ont été automatiquement créés par Odoo à la création du model. Les champs correspondent aux colonnes d'une table de base de données.

Ces champs automatiques sont nécessaire au fonctionnement interne d'Odoo.

Nous verrons plus tard comment ajouter nos propres champs à nos modèles.

Nous allons ici apprendre comment interagir en ligne de commande avec le gestionnaire de base de données qui s'exécute à l'intérieur de docker.

Pour exécuter le client psql, nous lanceront la commande suivante dans le terminal. (Il faut que le gestionnaire de base de données soit en cours d'exécution)

$ docker exec -it odoo_db psql -U postgres
psql (10.0)
Type "help" for help.

postgres=#

La commande précédente nous connecte avec l'utilisateur postgres sur la base de données de maintenance du même nom.

Nous allons dans ce qui suit

  • Nous connecter à la base de données nommée base que nous avons installée ici
  • Affichier le détail du modèle que nous avons créer avec l'ORM d'Odoo.
postgres=# \c base
You are now connected to database "base" as user "postgres".
base=# \d elo_prof
                                         Table "public.elo_prof"
   Column    |            Type             | Collation | Nullable |               Default
-------------+-----------------------------+-----------+----------+--------------------------------------
 id          | integer                     |           | not null | nextval('elo_prof_id_seq'::regclass)
 create_uid  | integer                     |           |          |
 create_date | timestamp without time zone |           |          |
 write_uid   | integer                     |           |          |
 write_date  | timestamp without time zone |           |          |
Indexes:
    "elo_prof_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "elo_prof_create_uid_fkey" FOREIGN KEY (create_uid) REFERENCES res_users(id) ON DELETE SET NULL
    "elo_prof_write_uid_fkey" FOREIGN KEY (write_uid) REFERENCES res_users(id) ON DELETE SET NULL
base=#

Relevons la différence qu'il y a entre la représentation du modèle dans Odoo et dans le gestionnaire de base de données.

elo.prof dans Odoo devient elo_prof dans le gestionnaire de base de données.

Notre modèle ne contient jusqu'à cette étape que les champs (colonnes) créés automatiquement par Odoo pour son fonctionnement interne.

En général, nous aurons besoin de définir des champs supplémentaires pour porter l'identité et le fonctionnement de notre modèle.

Pour cela, nous allons éditer notre modèle dans le fichier models.py pour lui ajouter de nouveaux champs.

models.py
from odoo import models, fields
 
class Professeur(models.Model):
    _name = 'elo.prof'
    _description = 'Professor Card'
 
    name = fields.Char(string="Professor Name")
    bio  = fields.Text(string="Short Bio")

Les champs des modèles sont définis comme des attributs. Ici, nous en créons deux, les champs name et bio qui sont respectivement de type Char et Text 9).

Les champs sont des instances de classes du module fields que nous avons importé à la première ligne en plus du module models.

Nous avons ajouté l'attribut spécial _description pour faire taire le WARNING vu lors de l'installation du module.

Nous rappelons encore une fois que modifier un fichier python nécessite le redémarrage de l'application Odoo. Ici, vu que nous avons modifié la définition d'un model, en ajoutant ou modifiant ses champs, nous devons en plus upgrader le module pour que ces modifications soient répercutées dans la base de données.

Pour mettre à jour notre module, nous revenons à la vue Apps et nous sélectionnons Upgrade après avoir appuyé sur les trois points d'extension verticaux dans le coin haut-droit du post-it kanban réservé à notre module.

Et voici donc ce qui apparaîtera dans votre terminal après avoir appuyé sur le bouton.

odoo  | .... INFO base odoo.addons.base.models.ir_module: ALLOW access to module.button_immediate_upgrade on ['monmodule'] to user admin #2 via 172.17.0.1
odoo  | .... INFO base odoo.addons.base.models.ir_module: ALLOW access to module.button_upgrade on ['monmodule'] to user admin #2 via 172.17.0.1
....
odoo  | .... INFO base odoo.modules.loading: loading 1 modules...
....
odoo  | .... INFO base odoo.modules.loading: Loading module monmodule (2/9)
odoo  | .... INFO base odoo.modules.registry: module monmodule: creating or updating database tables
....
odoo  | .... WARNING base odoo.modules.loading: The model elo.prof has no access rules, consider adding one. E.g. access_elo_prof,access_elo_prof,model_elo_prof,base.group_user,1,0,0,0
odoo  | .... INFO base odoo.modules.registry: verifying fields for every extended model
odoo  | .... INFO base odoo.modules.loading: Modules loaded.

Le WARNING sur l'absence de description du modèle a disparu mais le WARNING sur l'absence de règles d'accès (access rules) est toujours présent.

Nous verrons comment le traiter dans la partie suivante.

Mais avant cela nous allons examiner notre modèle dans Odoo et dans Postgresql pour voir nos modifications.

$ docker exec odoo_db psql -U postgres -d base -c '\d+ elo_prof'
                                                               Table "public.elo_prof"
   Column    |            Type             | Collation | Nullable |               Default                | Storage  | Stats target |   Description
-------------+-----------------------------+-----------+----------+--------------------------------------+----------+--------------+-----------------
 id          | integer                     |           | not null | nextval('elo_prof_id_seq'::regclass) | plain    |              |
 create_uid  | integer                     |           |          |                                      | plain    |              | Created by
 create_date | timestamp without time zone |           |          |                                      | plain    |              | Created on
 write_uid   | integer                     |           |          |                                      | plain    |              | Last Updated by
 write_date  | timestamp without time zone |           |          |                                      | plain    |              | Last Updated on
 name        | character varying           |           |          |                                      | extended |              | Professor Name
 bio         | text                        |           |          |                                      | extended |              | Short Bio
Indexes:
    "elo_prof_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "elo_prof_create_uid_fkey" FOREIGN KEY (create_uid) REFERENCES res_users(id) ON DELETE SET NULL
    "elo_prof_write_uid_fkey" FOREIGN KEY (write_uid) REFERENCES res_users(id) ON DELETE SET NULL

$

Sur les deux représentations du modèle elo.prof nous pouvons voir que les champs name et bio ont été correctement ajoutés.

Les droits d'accès sont le mécanisme utilisé pour définir les autorisations sur les modèles.

Grâce aux droits d'accès nous pouvons dire si tel groupe d'utilisateurs a le droit de lecture, de modification, de création ou d'effacement sur les enregistrements d'un modèle.

C'est un des nombreux mécanismes utilisables dans Odoo pour gérer les droits d'accès sur les modèles.

Pour implémenter les droits d'accès nous devons d'abord les déclarer dans le manifeste de notre module.

Nous allons donc éditer le fichier __manifest__.py ainsi :

__manifest__.py
{
    'name':'Mon Module',
    'data': [
        'ir.model.access.csv',
    ],
}

Nous avons ajouté au manifest une nouvelle clé data dont la valeur est une liste dont chaque élément est le nom d'un fichier qui est supposé contenir de la data.

Le nom de ce fichier correspond à un des modèles préchargés dans Odoo et dont Odoo se sert pour son fonctionnement interne.

Le modèle ir.model.access est le modèle qu'utilise Odoo pour conserver les droits d'accès sur les autres modèles.

Nous allons donc créer le ir.model.access.csv

$ cd ~/service.odoo/extra-addons/monmodule
$ touch ir.model.access.csv

Et nous allons le remplir avec le contenu suivant :

ir.model.access.csv
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_elo_prof,access_elo_prof,model_elo_prof,base.group_user,1,1,1,1
idnamemodel_id:idgroup_id:idperm_readperm_writeperm_createperm_unlink
access_elo_profaccess_elo_profmodel_elo_profbase.group_user1111

2)
Cette commande n'est à exécuter qu'une seule fois. Il ne sera plus nécessaire de le faire plus tard
3)
Nous verrons plus tard que cela n'est pas suffisant dans un certain cas de figure et qu'il faudra en plus upgrader son module dans le gestionnaire d'application de Odoo
4)
Le log de l'application est un des principaux outils de développement.
5)
Dans le cas d'une installation de base sans aucun module installé, ça sera la vue Apps qui liste les modules disponibles à l'installation
6)
La list complète des clés valables dans un fichier manifest de Odoo est accessible ici
7)
Filtrer signifie taper un mot sur la barre de recherche suivi d'Enter. Nous pouvons filtrer sur le nom mais aussi sur d'autres champs comme la catégorie ou l'état. Ces notions relèvent du fonctionnel de l'application Odoo et sont abordés sur un autre support
8)
Les règles d'accès seront abordées plus loin dans ce tuto
9)
Pour une liste complete des types de champs référez vous à Odoo ORM
  • development/odoo_dev_intro.txt
  • Last modified: 2022/11/13 15:18
  • by aziz