Lezione 3: Tabelle di lookup¶
In questa lezione parleremo delle tabelle di lookup, definendo la table cliente_tipo
. E inizieremo a migliorare la pagina di gestione della table cliente
.
La tabella cliente_tipo¶
Supponiamo che serva, per la nostra applicazione, suddividere i clienti secondo una tipologia.
Definiamo quindi la tabella cliente_tipo
con solo le colonne codice
e descrizione
.
class Table(object):
def config_db(self, pkg):
tbl = pkg.table('cliente_tipo', pkey='codice', name_long='Tipo cliente',
name_plural='Tipi cliente', caption_field='descrizione', lookup=True)
self.sysFields(tbl, id=False)
tbl.column('codice', size=':5', name_long='Codice')
tbl.column('descrizione', name_long='Descrizione')
In questo caso, a differenza di quanto fatto nella tabella cliente vogliamo che la primary key della tabella sia la colonna codice
e non la colonna id
di sistema. E questo lo facciamo specificando nel metodo table
il parametro pkey='codice'
ed impedendo l’aggiunta della colonna id
quando invochiamo la funzione sysFields
self.sysFields(tbl, id=False)
Questo genere di tabelle, caratterizzate da un numero molto limitato di righe, servono in genere a creare una scelta multipla di valori per il campo di una table: nel nostro caso il cliente_tipo
per la table cliente
.
Di norma per tabelle di questo tipo si usa come chiave primaria il codice stesso.
Nota
Tabelle di questo genere vengono definite in Genropy tabelle di lookup e sono caratterizzati dal parametro lookup=True
nella loro definizione. Mettere questo parametro a True
fa sì che la tabella possa essere visualizzata e riempita attraverso una pagina generica per la gestione delle tabelle lookup e non sarà necessario creare la risorsa th_cliente_tipo
.
Aggiungiamo poi al menu del package il gestore tabelle di lookup come mostrato
fatt.lookupBranch("Tabelle Ausiliarie", pkg="fatt")
O, nella sua versione legacy, precedente alla rivisitazione dei menu:
fatt.lookups(u"Tabelle Ausiliarie", lookup_manager="fatt")
Suggerimento
Per un approfondimento sui nuovi menu di Genropy si rimanda alla Guida ai Menu
Dopo aver riallineato il db con il comando gnrdbsetup e riattivato il server, usiamo il gestore tabelle di lookup nella nostra applicazione per caricare alcune voci nella tabella cliente_tipo.
Modifica tabella cliente¶
Dopo aver creato la tabella cliente_tipo
per utilizzarla modifichiamo il model di cliente
aggiungendo la colonna cliente_tipo_codice
.
Quindi metteremo questa colonna in relazione con la colonna codice
della table cliente_tipo
come foreign key.
tbl.column('cliente_tipo_codice', size=':5', name_long='Tipo cliente', name_short='Tipo').relation(
'cliente_tipo.codice',
relation_name='clienti',
mode='foreignkey',
onDelete='raise')
Adesso in modo del tutto analogo possiamo creare la tabella di lookup pagamento_tipo
e collegarla alla colonna pagamento_tipo_codice
che aggiungeremo nella table cliente
modificado il model.
Modifiche a th_cliente¶
Apriamo ora il modulo th_cliente.py
nelle risorse ed aggiungiamo alla view le colonne e alla form i relativi campi.
Nel frattempo miglioreremo l’aspetto della form utilizzando attributi come colspan e altri.
Nella form notiamo che i campi vengono aggiunti ad un oggetto di tipo formbuilder.
Il formbuilder è un elemento di interfaccia che serve a costruire delle form di campi che possono presentarsi affiancati su più colonne. Esso è basato su una tabella HTML, pertanto organizza i contenuti in righe e colonne.
Per avere dei margini corretti spostiamo il formbuilder all’interno di un div cui diamo l’attributo margin=10px.
class View(BaseComponent):
def th_struct(self,struct):
r = struct.view().rows()
r.fieldcell('ragione_sociale')
r.fieldcell('cliente_tipo_codice')
r.fieldcell('pagamento_tipo_codice')
r.fieldcell('indirizzo')
r.fieldcell('provincia')
r.fieldcell('comune_id')
def th_order(self):
return 'ragione_sociale'
def th_query(self):
return dict(column='ragione_sociale', op='contains', val='')
class Form(BaseComponent):
def th_form(self, form):
pane = form.record
fb = pane.div(margin='10px').formbuilder(
cols=2, border_spacing='4px', colswidth='auto', fld_width='100%')
fb.field('ragione_sociale', colspan=2)
fb.field('cliente_tipo_codice')
fb.field('pagamento_tipo_codice')
fb.field('indirizzo', colspan=2)
fb.field('provincia')
fb.field('comune_id', condition='$sigla_provincia=:provincia',
condition_provincia='^.provincia')
def th_options(self):
return dict(dialog_height='400px', dialog_width='600px')
Funzionamento del campo cliente_tipo¶
Dopo aver fatto aggiornare il db con il comando gnrdbsetup
e riattivato il server, torniamo ad osservare come si presenta la pagina di gestione della table cliente
. Notiamo i campi appena aggiunti sia nella view che nella form.
Possiamo selezionare un tipo cliente ma, dal momento che non abbiamo caricato alcun valore per il tipo pagamento, non potremmo selezionarli.
Cliccando sulla label del campo però si può aprire una palette, che permette di inserire direttamente gli elementi della tabella in relazione, in questo caso pagamento_tipo
.
La facoltà di accedere alle tabelle di lookup per inserire e modificare valori, può ovviamente essere limitata agli utenti che hanno gli adeguati tag di autorizzazione.
Ulteriori miglioramenti¶
Torniamo ora al model del cliente
e aggiungiamo le colonne note
e email
.
tbl.column('note', name_long="Note")
tbl.column('email', name_long='Email')
Andiamo quindi alla risorsa di Form e utiliziamo l’elemento BorderContainer
per dividere idealmente lo spazio della nostra pagina di form in più regioni.
Definiremo un contentPane
nella parte superiore (region =top
) che andrà a contenere la form con i dati principali del cliente.
Nello spazio rimanente definiamo un RoundedGroupFrame
destinato a contenere le note, per le quali utilizziamo un widget simpleTextArea
al quale l’attributo editor=True
fornirà un editor di testo formattato.
Inoltre per migliorare la leggibilità del codice definiremo dei metodi dedicati datiCliente
e noteCliente
in cui sviluppare le relative parti.
class Form(BaseComponent):
def th_form(self, form):
bc = form.center.borderContainer(datapath='.record')
self.datiCliente(bc.contentPane(region='top'))
self.noteCliente(bc.roundedGroupFrame(title='Note', region='center'))
def datiCliente(self, pane):
fb = pane.div(margin_left='50px', margin_right='80px').formbuilder(
cols=2, border_spacing='4px', colswidth='auto', fld_width='100%')
fb.field('ragione_sociale', colspan=2)
fb.field('cliente_tipo_codice')
fb.field('pagamento_tipo_codice')
fb.field('indirizzo', colspan=2)
fb.field('provincia')
fb.field('comune_id', condition='$sigla_provincia=:provincia',
condition_provincia='^.provincia')
fb.field('email', validate_email=True)
def noteCliente(self, pane):
pane.simpleTextArea(value='^.note', editor=True)
Allegati: