Blog

I campi dinamici in Genropy: istruzioni per l’uso

I campi dinamici in Genropy

Quando si progetta una base di dati può capitare di avere l’esigenza di avere in un’unica tabella significativa elementi che richiederebbero tracciati record diversi tra loro. Potrebbe essere il caso di alcune caratteristiche di un prodotto valide solo per una particolare tipologia di prodotto: è infatti più che probabile che alcuni attributi di una sedia (materiale, colore, altezza, tessuto) non saranno gli stessi necessari per identificare un tipo di vernice, così come le taglie di una maglietta (S,M,L) non saranno confrontabili con la misura delle scarpe (40, 41, ecc).

Dal momento che nei database relazionali i tracciati record sono omogenei, ovvero ogni riga di una tabella presenta le stesse colonne, come gestire questo tipo di casistica? Le strategie percorribili sarebbero fondamentalmente due:

  • creare più tabelle, una per ogni tipologia di record, ciascuna con le sue colonne specifiche; nel nostro caso specifico, creare più tabelle “arredamento”, “vernice”, “abbigliamento”, “scarpa”, e collegarle tutte a una tabella radice “prodotto”
  • aumentare a dismisura il numero di colonne, prevedendo che molte di esse resteranno vuote, in quanto non significative per alcune tipologie di record; ad es. creare quindi un’unica tabella “prodotto” che presenta tutte le colonne “colore”, “materiale”, “tessuto”, “misura”, pur sapendo che molte di queste che non verranno valorizzate

Entrambe le opzioni, seppur efficaci, non saranno efficienti dal punto di vista della strutturazione del nostro database. Come gestire quindi tutta questa eterogeneità nell’applicativo che gestisce il nostro magazzino o il nostro e-commerce? Esiste una terza strategia più efficiente?

In tutti questi casi l’appartenenza a un tipo prodotto (sulla base quindi di un prodotto_tipo_id), determina il set di opzioni possibili in termini di caratteristiche (misura, taglia, materiale, ecc.). Non sarebbe quindi bello poter definire tutti questi campi “dinamici” direttamente dall’interfaccia dell’applicativo invece di dover creare via codice tipo per tipo o replicare inutilmente le tabelle?

Per questo tipo di esigenza Genropy ci mette a disposizione i dynamic fields, ovvero una particolare funzionalità della table che permette di avere in una sola tabella tracciati record eterogenei a seconda del tipo di record.

Questo approccio richiede in fase di progettazione del model di definire due tabelle: quella principale (“master”) che conterrà i dati eterogenei, e la table “tipo” corrispondente. In quest’ultima andremo a definire i campi specifici, la loro Form e come questi campi devono essere visualizzati.

Un component apposito ci permetterà di creare dall’applicativo le Form per i campi specifici senza necessità di crearle una a una via codice, ed un altro component si occuperà di mostrare automaticamente a video i campi specifici al caricamento del record.


Come abilitare i Dynamic Fields: cosa fare sulla tabella “tipo”

L’abilitazione dei dynamic fields avviene su entrambe le tabelle coinvolte: in una tabella prodotto_tipo andremo infatti a specificare quali campi mostrare a seconda del tipo di prodotto, mentre nella tabella prodotto andremo a specificare i valori degli specifici campi abilitati per quel record.

Innanzitutto, quindi, nella tabella prodotto_tipo, andremo ad abilitare l’utilizzo dei campi dinamici semplicemente indicando nei sysFields della table l’attributo df=True:

class Table(object):
     def config_db(self, pkg):
         tbl = pkg.table('prodotto_tipo', pkey='id', name_long='Tipo prodotto', 
                 name_plural='Tipi prodotto', caption_field='hierarchical_descrizione')
         self.sysFields(tbl,hierarchical='descrizione',counter=True,df=True)
         tbl.column('descrizione', size=':50', name_long='Descrizione')

Allo stesso tempo nella risorsa th_prodotto_tipo andremo a mostrare la schermata di gestione dei campi dinamici utilizzando la FieldsGrid:

class Form(BaseComponent):
    py_requires = 'gnrcomponents/dynamicform/dynamicform:DynamicForm'

    def th_form(self, form):
        tc = form.center.tabContainer()
        tc.contentPane(title='Campi').fieldsGrid(margin='2px', rounded=6)

Queste semplicissime indicazioni di per sé saranno sufficienti a mostrare, all’inserimento di un nuovo prodotto_tipo, la schermata per la configurazione dei dynamic fields.

Sarà possibile scegliere un tipo di campo (es: text, decimal, boolean, ecc) da cui dipenderà di conseguenza il widget (es: textBox, numberTextBox, checkBox, ecc), sbloccando così alcuni campi speciali riservati a quello specifico tipo di campo (es: un “range” per i campi numerici). Sarà poi possibile personalizzare le cols, le colswidth, e indicare eventualmente una page (es: “alfa” o “beta”), così da riproporre un tab su cui vengono a loro volta suddivisi i campi.

dynamicfields form

Cosa fare sulla tabella “master”

Nel model della tabella prodotto, invece, andremo a creare un campo Bag dove inserire questi campi dinamici per ogni specifico prodotto:

tbl.column('caratteristiche', dtype='X', name_long='Caratteristiche', subfields='prodotto_tipo_id')

Si noti che in subfields andremo a indicare il nome della colonna in relazione.

Infine, nella Form della risorsa th andremo a inserire un dynamicFieldsPane che ci servirà a inserire i dynamic fields specificati per ogni singolo prodotto, se e solo se il prodotto in questione è del prodotto_tipo per il quale abbiamo specificato i df:

py_requires="gnrcomponents/dynamicform/dynamicform:DynamicForm"
...
def caratteristicheProdotto(self,pane):
    pane.dynamicFieldsPane('caratteristiche')

Ecco il risultato di questa semplice riga di codice:

Vuoi solo “incollare” i dynamic fields a un formbuilder già esistente, aggiungendo quindi i campi dinamici alla tua tabella? Puoi farlo facilmente utilizzando il metodo appendDynamicFields:

fb.appendDynamicFields('caratteristiche')

dove “caratteristiche” corrisponde al nome del campo Bag che abbiamo scelto.


È a questo punto facile intuire come l’uso dei Dynamic Fields possa rendere estremamente flessibile il nostro applicativo: sarà sufficiente attivare questa funzionalità per demandare poi all’interfaccia l’aggiunta o l’eventuale modifica di un qualsivoglia numero di campi.

Vuoi saperne di più? Puoi provare i Dynamic Fields in Sandbox, attivando le preferenze per i campi dinamici del magazzino. Clona subito Sandbox:

git clone https://github.com/genropy/sandbox/

Hai dubbi o domande? Scrivici su AskGenropy