Lezione 3: Tabelle di lookup

In questa terza 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')

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.

Hint

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.lookups(u"Tabelle Ausiliarie", lookup_manager="fatt")

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.

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)
_images/schermata-2019-04-16-alle-193616.png

Attachments: