Aggiornare più tabelle con un singolo form usando web2py

Se anche voi sviluppate in Python usando web2py, vi potrebbe capitare di voler aggiornare due o più tabelle del database utilizzando un singolo form all’interno di una vista.
La prima cosa che verrebbe in mente sarebbe quella di utilizzare SQLFORM oppure SQLFORM.factory perché sul libro mastro c’è un esempio
dettagliato su come inserire i record in più tabelle usando questi operatori. Quello che il manuale non dice è che funzionano soltanto per l’inserimento.
La seconda cosa da provare è una ricerca nella mailing-list web2py-users dove scoprirete che altri derelitti prima di voi sono incappati
nello stesso problema.
Alcune risposte propongono di specificare l’id del record da aggiornare all’interno dell’operatore SQLFORM.factory, in questo modo: SQLFORM.factory(db.tabella1,db.tabella2,record=id_del_record), non perdete tempo a provare, non funziona. E tantomeno funziona questo: SQLFORM.factory(db.tabella1,db.tabella2,id_del_record).
Per farla breve, ad oggi Febbraio 2015, esiste un’unica soluzione funzionante, indicata dallo stesso Massimo di Pierro nel lontano 2008 sulla mailing list web2py-users:

You have the option of using form=SQLFORM and then form[0].insert(2,TR
 (...)) the rows from the other table.
 It may be easier to create the form using form_factory.

Massimo

In parole povere, ad oggi Febbraio 2015, non c’è una reale soluzione e bisogna fare a manazza.

Ci sono due possibilità:

utilizzare SQLFORM per costruire il form della prima tabella e poi iniettare i campi delle altre tabelle nel form, oppure costruire tutto il form a mano usando form.factory. Dopodiché bisognerà gestire manualmente, dopo l’invio del form, l’aggiornamento/cancellazione dei record provenienti dalle altre tabelle correlate.
Dovendo inseire solamente un campo in più da un’altra tabella, ho scelto la prima opzione:

# Occorre una query per ottenere il record in tabella2 correlato al record in tabella1 che stiamo aggiornando
# questa qui sotto è solo un esempio
record_tabella2 = db(db.tabella2.id == id_del_record_in_tabella2)
# Creiamo il form principale tramite SQLFORM della tabella1
form = SQLFORM(db.tabella1,record_id,deletable=True,showid=True,compute=True)
# Costruiamo manualmente l'html del campo da aggiungere nella form
mio_campo_aggiuntivo = TR(LABEL('Campo aggiuntivo:'),TEXTAREA(_name='campo',value=tabella2.campo))
# Inseriamo il campo in posizione -1, ovvero sotto tutti gli altri campi
# attenzione che in questo modo il campo finira' sotto la spunta per l'eventuale cancellazione
form[0].insert(-1,mio_campo_aggiuntivo)
if form.process().accepted:
# Se viene cancellato il record in tabella1
# bisogna gestire la cancellazione del record correlato in db.tabella2
if form.vars.delete_this_record == 'on':
cancellazione_campo_aggiuntivo = db(db.tabella2.id == record_tabella2.id).delete()
else:
# Gestiamo l'aggiornamento del campo aggiuntivo
id_record_tabella2_aggiornato = db(db.tabella2.id == record_tabella2.id).validate_and_update(config=form.vars.config)
elif form.errors():
# blablabla
return dict(form=form)