Lezione 2: La tabella cliente

In questa seconda lezione vedremo come creare la prima table dei clienti e la pagina per gestirla.

La struttura di un package

Diamo un rapido sguardo a come è strutturato un package. Dopo la sua creazione troveremo all’interno della directory del package stesso (ovvero fatt nel nostro tutotial), il modulo main.py. In tale modulo viene data la definizione dell’oggetto Python corrispondente al package.

Vediamo che inoltre sono state generate alcune directory:

lib

Viene utilizzata molto raramente e serve a contenere eventuali librerie Python accessorie scritte per essere usate specificamente dal package.

model

Contiene i moduli relativi alla definizione delle tables del database e contiene le customizzazioni delle tables appartenenti ad altri packages.

resources

Contiene le risporse del package. Per risorse si intende un insieme di moduli (javascript, css, Python) che riguarderanno la parte front-end dell'applicazione. Gran parte delle risorse sono suddivise in directory chiamate come le tables del package. In modo tale che per ogni table ci sarà la corrispettiva directory contenente le sue resource di competenza. In particolare troveremo le th_resource, ovvero un tipo particolare di risorsa nella quale si definiscono le viste e le form di una table.

webpages

Contiene i moduli che definiscono alcune pagine realizzate appositamente per il package. Nella pratica comune, per presentare una pagina che consenta l'operatività su una table si usa lavorare sulla th_resource della table, vedremo in seguito come.

Creazione tabella cliente

Procediamo dunque a creare un file cliente.py nella cartella model e a definire in esso una classe Table che eredita da object. La classe Table deve essere vista solo come raccolta di metodi che in seguito saranno mixati alla vera classe della tabella.

Il metodo config_db riceve come parametro pkg che rappresenta il nostro package.

Definizione della table

def config_db(self, pkg):
      tbl = pkg.table('cliente', pkey='id', name_long='Cliente',
                      name_plural='Cliente', caption_field='ragione_sociale')

Definiamo i parametri principali della tabella:

  • pkey ovvero il campo primary key
  • name_long cioé il nome esteso della tabella al singolare
  • name_plural è al plurale
  • caption_field indica il campo che verrà usato come etichetta del record. Può essere un campo singolo o composto da più campi. In questo caso per rappresentare il cliente usiamo la sua ragione_sociale.

Definizione delle colonne

Con l'istruzione self.sysField() vengono aggiunte automaticamente alcune colonne di sistema come:

  • la primary key id
  • il timestamp di inserimento __ins_ts
  • il timestamp di ultima modifica __mod_ts
tbl.column('ragione_sociale',
            size=':40',
            name_long='Ragione sociale',
            name_short='Rag. Soc.')

il primo parametro è il nome della colonna, size si usa per le colonne di tipo CHAR o VARCHAR ed indica il numero di caratteri, mentre name_long e name_short si riferiscono a come la colonna verrà etichettata nelle griglie e nelle form.

Quindi vengono poi definite le colonne con il metodo column - ragione_sociale - indirizzo - provincia - comune_id

Queste ultime colonne hanno una relazione con le tabelle provincia e comune del package glbl.

Relazioni

Per stabilire una relazione si usa il metodo relation()

provincia.relation('glbl.provincia.sigla',
                         relation_name='clienti',
                         mode='foreignkey',
                         onDelete='raise')

che consente di definire per la relazione il campo collegato, il nome della relazione ed altri parameteri. Il primo parametro contiene la colonna in relazione, ovvero sigla della table provincia, del package glbl.

relation_name è come viene nominata la relazione dal punto di vista della table in relazione, in questo caso la provincia. Vale a dire che per la table provincia, seguendo questa relazione ritrovo i clienti appartenenti ad essa.

mode='foreignkey' indica che la relazione viene riportata anche nel database come una foreignkey a tutti gli effetti, con i vincoli che ne conseguono.

Dunque alla fine la definizione della table cliente sarà la seguente:

class Table(object):
    def config_db(self, pkg):
        tbl = pkg.table('cliente', pkey='id', name_long='Cliente',
                      name_plural='Cliente', caption_field='ragione_sociale')
        self.sysFields(tbl)

        tbl.column('ragione_sociale', size=':40', name_long='Ragione sociale', name_short='Rag. Soc.')

        tbl.column('indirizzo', name_long='Indirizzo')
        provincia = tbl.column('provincia', size='2', name_long='Provincia', name_short='Pr.')
        provincia.relation('glbl.provincia.sigla',
                         relation_name='clienti',
                         mode='foreignkey',
                         onDelete='raise')
        tbl.column('comune_id', size='22', group='_',   name_long='Comune').relation('glbl.comune.id',
                                                                                  relation_name='clienti',
                                                                                  mode='foreignkey',
                                                                                  onDelete='raise')

Creazione risorsa th_cliente

Ora lanciamo da console il comando

>>>  gnrmkthresource fatturazione:fatt -m

Hint

Questo comando non deve essere lanciato dall'interno della directory fatt, ma da qualsiasi altro punto.

Questo script provvede alla creazione automatica delle risorse th_resource corrispondenti alle tabelle già definite nel model pacchetto fatt. In questo caso solamente cliente. Di norma per ogni tabella si definisce un modulo che ha lo stesso nome della tabella prefissato da th_. Il prefisso th sta per table handler che, come vedremo in seguito, è il component che gestisce le pagine per la gestione delle tabelle. In questo caso notiamo che il comando ha generato all' interno della cartella resources/tables/cliente il modulo th_cliente.py.

Con l'opzione -m abbiamo fatto generare anche il modulo menu.py dentro la directory del package. Di questo file parleremo in seguito.

Per un approfondimento sul funzionamento delle pagine ottenute definendo le risorse table handler vi rimandiamo alla spiegazione fornita dal Manuale utente di Genropy

Classe View

In ogni modulo di tipo th_resource possono essere presenti diverse classi di tipo view. La classe denominata View è quella di default.

Le classi di tipo view sono quelle che implementano il metodo th_struct il quale definisce la vista, ovvero le colonne da visualizzare in una griglia.

Vi sono inoltre altri metodi quali th_order che definisce l'ordinamento di default, e th_query che imposteranno i parametri di default per la query iniziale sulla table.

L'implementazione di th_struct incomincia sempre con la definizione di un elemento rows sul quale si aggiungono gli elementi fieldcell che rappresentano le colonne della table che vogliamo presentare a video, nella nostra griglia.

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='')

Classe Form

In ogni modulo di tipo th_resource possono anche essere presenti diverse classi di tipo form che essenzialmente sono le classi che implementano il metodo th_form.

La classe denominata Form che troviamo già nel file è quella di default. Una classe di form definisce la pagina che ci troviamo di fronte quando l'utente entra in modalità inserimento o modifica di un singolo record.

Nella sua forma più essenziale conterrà la form con i campi di input della tabella a cui si riferisce la risorsa. Ma vedremo che è possibile sviluppare anche layout molto più complessi ed articolati.

class Form(BaseComponent):

  def th_form(self, form):
      pane = form.record
      fb = pane.formbuilder(cols=2, border_spacing='4px')
      fb.field('ragione_sociale')
      fb.field('indirizzo')
      fb.field('provincia')
      fb.field('comune_id')

Il modulo menu.py

Verifichiamo ora come è stato creato il file menu.py che definisce la struttura gerarchica del menu di navigazione dell'applicazione.

Apriamolo e modifichiamolo come segue.

def config(root,application=None):
  fatt = root.branch(u"Fatturazione")
  fatt.thpage(u"!!Cliente", table="fatt.cliente")

L'elemento branch crea una sorta di directory, mentre l'elemento thpage crea il collegamento con la pagina standard di gestione di tabella, la quale utilizzerà le classi view e form definite dalla th_resource th_cliente.py

Hint

Nel filmato parla invece di un file menu.xml . Adesso i menu vengono gestiti da moduli Python.

Aggiorniamo il database

Dal terminale eseguiamo il comando

>>> gnrdbsetup myfatturazione

Per far sì che automaticamente il database si aggiorni secondo le modifiche stabilite nei file che si trovano nella directory model.

Verifichiamo il risultato

Riavviamo nuovamente il server

>>> gnrwsgiserve myfatturazione

E andiamo a vedere con il browser cosa troviamo nella nostra applicazione. Notiamo subito che nel menu è comparsa la voce cliente nella directory di menu del package fatturazione. Selezionandola viene aperta la pagina cliente e con il bottone + procediamo a creare un record cliente.

La form creata in automatico non è particolarmente bella ma consente comunque di caricare i dati del nostro primo cliente. Notiamo che per i campi provincia e comune viene abilitata la ricerca sull'archivio in relazione corrispondente. Il fatto che un campo sia ricercabile è evidenziato dallo sfondo giallo. Inoltre, per la relazione su provincia, è anche abilitata un'icona a freccia per mostrare gli elementi. Per relazioni ad archivi ad alta numerosità, di norma l'icona a freccia viene omessa.

Utilizzando la ricerca sul campo comune notiamo però che tale ricerca non sia limitata ai comuni della provincia selezionata. Se vogliamo restringere la scelta dei comuni alla provincia selezionata, provvediamo ad aggiungere al field del campo comune_id un parametro condition all'interno della classe form definita dalla th_resource th_cliente.py, come mostrato

fb.field('comune_id', condition='$sigla_provincia=:provincia', condition_provincia='^.provincia')

Questo farà sì che nella query degli elementi selezionabili dal widget sia aggiunta la condizione che la provincia del comune sia uguale alla provincia già inserita nel campo provincia.

Attachments: