Tutti i campi che abbiamo definito fin qui sono gestiti manualmente. L’utente entra in modalità modifica di un oggetto, aggiorna i valori e preme salva. Oddo permette però di avere altri campi il cui valore non viene definito direttamente dall’utente ma viene invece calcola attraverso una funzione.
Un computed field viene dichiarato esattamente come i campi normali con l’unica differenza di avere un parametro compute che indica la funzione che Odoo utilizzerà per calcolarne il valore.
Immaginiamo per esempio di voler mantenere nei TodoTask l’informazione relativa allora stato del progetto a cui appartengono. Gestire questo dato a mano sarebbe piuttosto oneroso, un computed field invece risolve il problema egregiamente.
Per aggiunger questo campo al nostro modello dei progetti apriamo il file models/task_task.py e aggiungiamo nel corpo della classe:
project_state = fields.Char(string='Project state', compute='_compute_project_state')
@api.depends('project_id')
def _compute_project_state(self):
for todo in self:
todo.project_state = todo.project_id.state
Il decoratore @api.depends indica a Odoo di calcolore il valore del campo solo dopo aver modificato il valore dei campi espressi nel decoratore. Quindi in questo caso verrà ricalcolato il contatore solo quando modificheremo il valore del campo project_id.
Nel file delle viste dei progetti views/task_task.xml modifichiamo la Form View per visualizzare questo valore. Aggiungiamo nel campo arch:
<field name='name' position='after'>
<field name='project_id'/>
<field name='project_state'/>
</field>
ricarichiamo la pagina
Ora è presente il lo stato del progetto, se proviamo a chiudere il progetto vedremo che la stessa informazione si aggiornera anche su tutti i suoi Todo.
I computed field non possono essere usati come filtro sull’oggetto in cui vengono definiti a meno di non implementare esplicitamente una funzione di ricerca. Quindi a fianco al parametro compute, dobbiamo passargli anche un argomento search specificado il nome della funzione che vogliamo utilizzare.
Nella nostra class TodoTask modifichiamo l’attributo project_state
project_state = fields.Char(string='Stato progetto',
compute='_compute_project_state',
search='_search_project_state',)
e tra i metodi aggiungiamo:
def _search_project_state(self, operator, value):
return [('project_id', operator, value)]
È anche possibile specificare una funzione che permetta di scrivere i computed fields. Questa funzione si prende carico di normalizzare l’input per forlo arrivare al database nel modo corretto. Al pari di compute e search, la funzione si specifica tra i parametri del campo con il nome di inverse:
Modifichiamo il campo aggiungendo il parametro inverse:
project_state = fields.Char(string='Stato progetto',
compute='_compute_project_state',
search='_search_project_state',
inverse='_write_project_state')
e tra i metodi aggiungiamo:
def _write_project_state(self):
self.project_id.state = self.project_state
Un’altra possibilità è quella di comunicare ad Odoo di salvare il valore del computed field in database. Dal momento che i valori vengono salvati a database non sarà più necessario specificare le funzioni search e inverse perchè Odoo sarà già in grado di gestirle in autonomia. Per salvare un computed field in database è sufficiente specificare store=True tra i parametri del campo.
Il computed field che abbiamo implementato è un classico: si occupa semplicemente di copiare il valore di un campo di un oggetto correlato al nostro. Questo tipo di comportamento può essere gestito in completa autonomia da Odoo, senza dover per forza esplicitare tutte le funzioni necessarie.
I related fields si dichiarano nello stesso modo dei computed field ma specificanto l’argomento related anzichè compute. Il valore dell’argomento related sarà una stringa in dotted-notation che identifica il campo che si vuole relazionare.
Nel nostro caso sarebbe:
project_state = fields.Char(string='Stato progetto', related='project_id.state')
Per terminare la nostra panoramica sui modelli, vediamo ora come possiamo esprimere dei vincoli d’integrità per i nostri dati.