Definire classi View e Form alternative

Come accennato precedentemente, view diverse possono avere, nella funzione th_struct, set diversi di colonne da visualizzare.

È possibile quindi avere view diverse con strutture diverse ed è anche possibile condizionare la view da utilizzare condizionando la view in funzione del contenuto di una o più colonne del modello. Tutto questo viene descritto nella sezione dedicata ai Metodi avanzati .

Come accennato precedentemente, un file risorsa può avere al suo interno la definizione di più view utilizzabili in modalità diverse e con scopi diversi. Tra i metodi più complessi, esiste la possibilità di condizionare la view con una determinata struttura condizionandone la visualizzazione anche in base al contenuto di una colonna della tabella, ma tutto questo verrà affrontato nei metodi avanzati; tuttavia esiste anche un metodo semplice di utilizzo di view diverse view selezionabili dall’utente in situazioni diverse.

Facciamo un esempio.

Facciamo riferimento sempre alla tabella cliente di Sandbox e supponiamo di avere una tabella con molte colonne tanto da voler suddividere la sua visualizzazione (in base a contesti diversi) in una vista «ridotta» e una «completa» (default) in questo modo:

class View(BaseComponent):
  def th_struct(self,struct):
      r = struct.view().rows()
      r.fieldcell('ragione_sociale')
      r.fieldcell('cliente_tipo_codice')
      r.fieldcell('indirizzo')
      r.fieldcell('comune_id')
      r.fieldcell('provincia')

  def th_order(self):
      return 'ragione_sociale'

  def th_query(self):
      return dict(column='ragione_sociale', op='contains', val='')

  def th_options(self):
      return dict(virtualStore=False)

class ViewRidotta(BaseComponent):
  def th_struct(self,struct):
      r = struct.view().rows()
      r.fieldcell('ragione_sociale')
      r.fieldcell('cliente_tipo_codice')

  def th_order(self):
      return 'ragione_sociale'

  def th_query(self):
      return dict(column='ragione_sociale', op='contains', val='')

  def th_options(self):
      return dict(virtualStore=True)

Le due view (quella di default) e la ViewRidotta, anche con virtualStore diversi, possono essere associate a due voci del menù diverse:

def config(root,application=None):
  fatturazione = root.branch(u"Fatturazione")
  fatturazione.thpage(u"Clienti Completa", table="fatt.cliente")
  fatturazione.thpage(u"Clienti Ridotta", table="fatt.cliente",     viewResource='ViewRidotta')

Sarà sufficiente specificare, nell’ultima riga, che la viewResource da utilizzare non deve essere quella di default, ma quella specificata dal parametro.

Vediamo ora un altro esempio in cui con pochissime modifiche al codice metteremo in atto le seguenti modifiche.


  1. Viene modificato l’ordinamento dei dati presentati in griglia per nome dell’artista e poi per nome della traccia
class ViewArtist(BaseComponent):

  def th_struct(self,struct):
      r = struct.view().rows()
      r.fieldcell('@albumid.@artistid.name', name='Artist')
      r.fieldcell('name', name='Track')
      r.fieldcell('albumid', name='Album')

  def th_order(self):
      return '@albumid.@artistid.name, name'
  1. Con RunOnStart=True viene attivata l’esecuzione della query al caricamento della pagina.
def th_query(self):
    return dict(column='name', op='contains', val='', runOnStart=True)
  1. Con widget='dialog' il record viene mostrato in una finestra di dialogo invece che in una nuova pagina (passaggio da stackTableHandler a dialogTableHandler). Inoltre con readOnly=True questa finestra viene resa di sola lettura.
def th_options(self):
    return dict(widget='dialog', readOnly=True)
  1. Viene aggiunta una bottoniera di sections per filtrare i dati in selezione.
def th_top_toolbarsuperiore(self,top):
    top.slotToolbar('*,sections@mediatypeid,*', childname='superiore', _position='<bar')
  1. Viene Sostituita la query generica con querybysample più specifiche e più immediate.
def th_queryBySample(self):
    return dict(fields=[dict(field='@albumid.@artistid.name', lbl='Artist', width='20em'),
                        dict(field='@genreid.name', lbl='Genre', width='20em')],
                        cols=2, isDefault=True)
  1. Infine, viene modificata la Form , rendendola di sola visualizzazione, ed offrendo la possibilità di acquistare la canzone tramite un bottone “Buy” (che in realtà farà un semplice alert a video).
::

class FormPurchase(BaseComponent):

def th_form(self, form):
pane = form.record fb = pane.formbuilder(cols=1, border_spacing=“4px”) fb.field(“name”) fb.field(“albumid”) fb.field(“mediatypeid”) fb.field(“genreid”) fb.field(“unitprice”) fb.button(“Buy”, action=”alert(«Good choice!»)”) fb.button(“Do NOT Buy”, action=”this.form.abort()”)
def th_options(self):
return dict(readOnly=True, modal=True)

Metodi alternativi per ridefinire parti delle view

Nei casi d’uso normali, anche in applicazioni non particolarmente complesse si ha spesso la necessità di definire delle view accessorie o alternative rispetto alla view principale. In questo caso viene spontaneo ed immediato duplicare il codice della view principale, rinominado la nuova view, per poi modificarne la struttura e/o altri metodi, e adattare la nuova vista alle specifiche necessità che molto spesso richiedono delle modifiche modeste.

In questi casi, torna utile, per evitare la duplicazione di codice rindondante, sfruttare l’ereditarietà degli oggetti; vediamo meglio come procedere e quali sono i vantaggi.

si supponga di avere una view (base)nella quale sono definiti i seguenti metodi:

class View(BaseComponent):
  def th_struct(self,struct):
    r.fieldcell('a')
    r.fieldcell('b')
    r.fieldcell('c')
    #...

  def th_order(self):
    #...

  def th_query(self):
    #...

  def th_options(self):
    #...

supponiamo ora di avere la necessità di definire nella nostra applicazione una nuova view (che chiameremo ViewEstesa), che rispetto alla view di base debba aggiungere una queryBySample, e magari aggiungere una colonna alla th_struct, mentre il resto vada già bene com’è. Sfruttando l’ereditarietà possiamo definire una nuova classe come segue:

class ViewEstesa(View):
 def th_struct(self,struct):
   r.fieldcell('a')
   r.fieldcell('b')
   r.fieldcell('c')
   r.fieldcell('importo', width='10em', totalize=True,
   #...

 def th_queryBySample(self):
  #....

La particolarità sta nel fatto che in questa nuova view non eredita da BaseComponent (o BaseView) ma da View, ovvero è da questa view principale della risorsa che eredita tutte le definizioni.

A questo punto possiamo fare due cose:

  1. sovrascrivere un metodo della view di base (ad esempio il th_struct per aggiungere una nuova colonna)
  2. aggiungere un nuovo metodo per definire una queryBySample

Quindi la nuova view avrà dei metodi propri specifici (quelli ridefiniti) e uno o più metodi aggiuntivi non presenti nella view base, ma gli altri metodi rimangono quelli della view di base (th_order,th_options e th_query).

In questo modo si evita la duplicazione di parti di codice rindondanti ed inutili e soprattutto in fase di modifica del codice si può intervenire (qualora questo sia sufficiente) solo su un singolo pezzo e solo su un punto del modulo.

Autore della sezione: Valter Vettorello