SlideShare una empresa de Scribd logo
1 de 76
Descargar para leer sin conexión
Un progetto in
                          GenroPy
                          Framework tutto italiano
                        per applicazioni web e AJAX




sabato 29 maggio 2010
Un progetto in
                          GenroPy
                          Framework tutto italiano
                        per applicazioni web e AJAX
                                           stionali
                                         ge




sabato 29 maggio 2010
Roberto Lupi
                                         @robertolupi
                   •    10 anni di esperienza web
                   •    enterprise e intranet
                   •    Clienti: Amadori, Merloni, 21 banche
                   •    Italia e India
                   •    oggi: direttore tecnico di MedMedia
                        software per la sanità
                   •    http://www.medmediagroup.it/


sabato 29 maggio 2010
Siti vs. applicazioni



sabato 29 maggio 2010
X
                                                             M
                                                             L
                                O                                           Web AJAX
                        Base                                  /
                        dati
                                R        Business logic
                                M                                             PDF
                                                              J
                                                              S
                                                              O
                                                              N


                               !
                          Object-relational
                                                            !
                                                     domain objects / GUI
                          RDBMS
                        impedance mismatch          domain objects
                                                     impedance mismatch

                         vs. objects                   vs. GUI


sabato 29 maggio 2010
✗
                        HTML



sabato 29 maggio 2010
Personalizzazioni?




sabato 29 maggio 2010
Stampe?



sabato 29 maggio 2010
La storia



sabato 29 maggio 2010
Stan
sabato 29 maggio 2010
Il progetto




sabato 29 maggio 2010
Il progetto




         15 processi
        amministrativi


sabato 29 maggio 2010
Il progetto




         15 processi       200+ forms
        amministrativi        Web


sabato 29 maggio 2010
Il progetto




         15 processi       200+ forms   190 reports e
        amministrativi        Web        forms PDF


sabato 29 maggio 2010
Il progetto




         15 processi       200+ forms   190 reports e
        amministrativi        Web        forms PDF


sabato 29 maggio 2010
sabato 29 maggio 2010
2 sviluppatori




sabato 29 maggio 2010
2 sviluppatori   2 designers




sabato 29 maggio 2010
2 sviluppatori   2 designers   2 mesi




sabato 29 maggio 2010
sabato 29 maggio 2010
GenroPy



sabato 29 maggio 2010
sabato 29 maggio 2010
Bags



sabato 29 maggio 2010
valori ed attributi
           simile a XML
                gerarchica ed ordinata



                                  Bags



sabato 29 maggio 2010
valori ed attributi
           simile a XML
                gerarchica ed ordinata



                                  Bags

                                         observer pattern
                                               dinamica
                                                    lazy loading

sabato 29 maggio 2010
valori ed attributi
           simile a XML
                gerarchica ed ordinata



                                          Bags

                                             observer pattern
   web services         database                   dinamica
              versatile                                 lazy loading
   files XML             directory trees
sabato 29 maggio 2010
domain specific
     valori ed attributi                         base dati      languages
           simile a XML                             universale
                gerarchica ed ordinata            interfaccia utente



                                          Bags

                                             observer pattern
   web services         database                    dinamica
              versatile                                      lazy loading
   files XML             directory trees
sabato 29 maggio 2010
X
                                           M
                                           L
                         O   Business              Web AJAX
                  Base                         /
                  dati
                         R              Bags
                         M    Logic                  PDF
                                               J
                                               S
                                               O
                                               N




sabato 29 maggio 2010
Database



sabato 29 maggio 2010
Quasi un ORM...

                        class Table(object):

                            def config_db(self, pkg):
                                tbl = pkg.table('user', pkey='id', name_long='!!User', rowcaption='username,email:%s (%s)')
                                self.sysFields(tbl,ins=True, upd=True, md5=True)
                                tbl.column('id',size='22',group='_',readOnly='y',name_long='Id')
                                tbl.column('username', size=':32',name_long='!!Username', unique='y', _sendback=True,
                                            indexed='y',validate_notnull=True,validate_notnull_error='!!Mandatory field')
                                tbl.column('email',name_long='Email',validate_notnull=True,
                                            validate_notnull_error='!!Mandatory field')
                                tbl.column('firstname', size=':32',name_long='!!First name',
                                            validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field')
                                tbl.column('lastname', size=':32',name_long='!!Last name',
                                            validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field')
                                tbl.column('registration_date', 'D' ,name_long='!!Registration Date')
                                tbl.column('auth_tags', name_long='!!Authorization Tags')
                                tbl.column('status', name_long='!!Status', size='4',
                                                  validate_values_conf='!!Confirmed',
                                                  validate_values_wait='!!Waiting')
                                tbl.column('md5pwd', name_long='!!PasswordMD5', size=':65')
                                tbl.column('locale', name_long='!!Default Language', size=':12')
                                tbl.column('preferences', dtype='X', name_long='!!Preferences')
                                tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name')

                            # ... metodi d'utilità ...

                            def trigger_onUpdating(self, record,**kwargs):
                                # ...

                            def trigger_onInserting(self, record,**kwargs):
                                # ...




sabato 29 maggio 2010
Quasi un ORM...

                        class Table(object):

                            def config_db(self, pkg):
                                tbl = pkg.table('user', pkey='id', name_long='!!User', rowcaption='username,email:%s (%s)')
                                self.sysFields(tbl,ins=True, upd=True, md5=True)
                                tbl.column('id',size='22',group='_',readOnly='y',name_long='Id')
                                tbl.column('username', size=':32',name_long='!!Username', unique='y', _sendback=True,
                                            indexed='y',validate_notnull=True,validate_notnull_error='!!Mandatory field')
                                tbl.column('email',name_long='Email',validate_notnull=True,
                                            validate_notnull_error='!!Mandatory field')
                                tbl.column('firstname', size=':32',name_long='!!First name',
                                            validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field')
                                tbl.column('lastname', size=':32',name_long='!!Last name',
                                            validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field')
                                tbl.column('registration_date', 'D' ,name_long='!!Registration Date')
                           tbl.column('id',size='22',group='_',readOnly='y',name_long='Id')
                                tbl.column('auth_tags', name_long='!!Authorization Tags')
                                tbl.column('status', name_long='!!Status', size='4',
                                                  validate_values_conf='!!Confirmed',
                                                  validate_values_wait='!!Waiting')
                                tbl.column('md5pwd', name_long='!!PasswordMD5', size=':65')
                                tbl.column('locale', name_long='!!Default Language', size=':12')
                                tbl.column('preferences', dtype='X', name_long='!!Preferences')
                                tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name')

                            # ... metodi d'utilità ...

                            def trigger_onUpdating(self, record,**kwargs):
                                # ...

                            def trigger_onInserting(self, record,**kwargs):
                                # ...




sabato 29 maggio 2010
Quasi un ORM...

                        class Table(object):

                            def config_db(self, pkg):
                                tbl = pkg.table('user', pkey='id', name_long='!!User', rowcaption='username,email:%s (%s)')
                                self.sysFields(tbl,ins=True, upd=True, md5=True)
                                tbl.column('id',size='22',group='_',readOnly='y',name_long='Id')
                                tbl.column('username', size=':32',name_long='!!Username', unique='y', _sendback=True,
                                            indexed='y',validate_notnull=True,validate_notnull_error='!!Mandatory field')
                                tbl.column('email',name_long='Email',validate_notnull=True,
                                            validate_notnull_error='!!Mandatory field')
                                tbl.column('firstname', size=':32',name_long='!!First name',
                                            validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field')
                                tbl.column('lastname', size=':32',name_long='!!Last name',
                                            validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field')
                                tbl.column('registration_date', 'D' ,name_long='!!Registration Date')
                           validate_notnull=True,validate_notnull_error='!!Mandatory field'
                                tbl.column('auth_tags', name_long='!!Authorization Tags')
                                tbl.column('status', name_long='!!Status', size='4',
                                                  validate_values_conf='!!Confirmed',
                                                  validate_values_wait='!!Waiting')
                                tbl.column('md5pwd', name_long='!!PasswordMD5', size=':65')
                                tbl.column('locale', name_long='!!Default Language', size=':12')
                                tbl.column('preferences', dtype='X', name_long='!!Preferences')
                                tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name')

                            # ... metodi d'utilità ...

                            def trigger_onUpdating(self, record,**kwargs):
                                # ...

                            def trigger_onInserting(self, record,**kwargs):
                                # ...




sabato 29 maggio 2010
Quasi un ORM...

                        class Table(object):

                        def config_db(self, pkg):
                            tbl = pkg.table('user', pkey='id', name_long='!!User', rowcaption='username,email:%s (%s)')
                            self.sysFields(tbl,ins=True, upd=True, md5=True)
                            tbl.column('id',size='22',group='_',readOnly='y',name_long='Id')
                            tbl.column('username', size=':32',name_long='!!Username', unique='y', _sendback=True,
                                        indexed='y',validate_notnull=True,validate_notnull_error='!!Mandatory field')
                            tbl.column('email',name_long='Email',validate_notnull=True,
                                        validate_notnull_error='!!Mandatory field')
                            tbl.column('firstname', size=':32',name_long='!!First name',
                                        validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field')
                            tbl.column('lastname', size=':32',name_long='!!Last name',
                                        validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field')
                            tbl.column('registration_date', 'D' ,name_long='!!Registration Date')
                    tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name')
                            tbl.column('auth_tags', name_long='!!Authorization Tags')
                            tbl.column('status', name_long='!!Status', size='4',
                                              validate_values_conf='!!Confirmed',
                                              validate_values_wait='!!Waiting')
                            tbl.column('md5pwd', name_long='!!PasswordMD5', size=':65')
                            tbl.column('locale', name_long='!!Default Language', size=':12')
                            tbl.column('preferences', dtype='X', name_long='!!Preferences')
                            tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name')

                            # ... metodi d'utilità ...

                            def trigger_onUpdating(self, record,**kwargs):
                                # ...

                            def trigger_onInserting(self, record,**kwargs):
                                # ...




sabato 29 maggio 2010
Quasi un ORM...

                        class Table(object):

                            def config_db(self, pkg):
                                tbl = pkg.table('user', pkey='id', name_long='!!User', rowcaption='username,email:%s (%s)')
                                self.sysFields(tbl,ins=True, upd=True, md5=True)
                                tbl.column('id',size='22',group='_',readOnly='y',name_long='Id')
                                tbl.column('username', size=':32',name_long='!!Username', unique='y', _sendback=True,
                                            indexed='y',validate_notnull=True,validate_notnull_error='!!Mandatory field')
                                tbl.column('email',name_long='Email',validate_notnull=True,
                                            validate_notnull_error='!!Mandatory field')
                                tbl.column('firstname', size=':32',name_long='!!First name',
                                            validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field')
                                tbl.column('lastname', size=':32',name_long='!!Last name',
                                        def trigger_onUpdating(self, record,**kwargs):
                                            validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field')
                                                   # ...
                                tbl.column('registration_date', 'D' ,name_long='!!Registration Date')
                                tbl.column('auth_tags', name_long='!!Authorization Tags')
                                tbl.column('status', name_long='!!Status', size='4',
                                        def trigger_onInserting(self, record,**kwargs):
                                                  validate_values_conf='!!Confirmed',
                                                   # ...
                                                  validate_values_wait='!!Waiting')
                                tbl.column('md5pwd', name_long='!!PasswordMD5', size=':65')
                                tbl.column('locale', name_long='!!Default Language', size=':12')
                                tbl.column('preferences', dtype='X', name_long='!!Preferences')
                                tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name')

                            # ... metodi d'utilità ...

                            def trigger_onUpdating(self, record,**kwargs):
                                # ...

                            def trigger_onInserting(self, record,**kwargs):
                                # ...




sabato 29 maggio 2010
GUI



sabato 29 maggio 2010
✗
                        HTML



sabato 29 maggio 2010
Dojo



sabato 29 maggio 2010
AJAX semplicissimo
                        class GnrCustomWebPage(object):
                            def windowTitle(self):
                                 return '!!Hello world'

                            def main(self, root, **kwargs):
                                tabber = root.tabContainer()
                                tab = tabber.contentPane(title='Tab')
                                tab.button('Che ore sono?',action='FIRE chiedi_ora;')
                                root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora')
                                tab.div('^risultato')

                            def rpc_dammi_ora(self):
                                return datetime.datetime.now()




sabato 29 maggio 2010
AJAX semplicissimo
                        class GnrCustomWebPage(object):
                            def windowTitle(self):
                                 return '!!Hello world'

                            def main(self, root, **kwargs):
                                tabber = root.tabContainer()
                                tab = tabber.contentPane(title='Tab')
                                tab.button('Che ore sono?',action='FIRE chiedi_ora;')
                                root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora')
                                tab.div('^risultato')

                            def rpc_dammi_ora(self):
                                return datetime.datetime.now()




sabato 29 maggio 2010
AJAX semplicissimo
                        class GnrCustomWebPage(object):
                            def windowTitle(self):
                                 return '!!Hello world'

                            def main(self, root, **kwargs):
                                tabber = root.tabContainer()
                                tab = tabber.contentPane(title='Tab')
                                tab.button('Che ore sono?',action='FIRE chiedi_ora;')
                                root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora')
                                tab.div('^risultato')

                            def rpc_dammi_ora(self):
                                return datetime.datetime.now()




sabato 29 maggio 2010
AJAX semplicissimo
                        class GnrCustomWebPage(object):
                            def windowTitle(self):
                                 return '!!Hello world'

                            def main(self, root, **kwargs):
                                tabber = root.tabContainer()
                                tab = tabber.contentPane(title='Tab')
                                tab.button('Che ore sono?',action='FIRE chiedi_ora;')
                                root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora')
                                tab.div('^risultato')

                            def rpc_dammi_ora(self):
                                return datetime.datetime.now()




sabato 29 maggio 2010
AJAX semplicissimo
                        class GnrCustomWebPage(object):
                            def windowTitle(self):
                                 return '!!Hello world'

                            def main(self, root, **kwargs):
                                tabber = root.tabContainer()
                                tab = tabber.contentPane(title='Tab')
                                tab.button('Che ore sono?',action='FIRE chiedi_ora;')
                                root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora')
                                tab.div('^risultato')

                            def rpc_dammi_ora(self):
                                return datetime.datetime.now()




sabato 29 maggio 2010
AJAX semplicissimo
                        class GnrCustomWebPage(object):
                            def windowTitle(self):
                                 return '!!Hello world'

                            def main(self, root, **kwargs):
                                tabber = root.tabContainer()
                                tab = tabber.contentPane(title='Tab')
                                tab.button('Che ore sono?',action='FIRE chiedi_ora;')
                                root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora')
                                tab.div('^risultato')

                            def rpc_dammi_ora(self):
                                return datetime.datetime.now()




sabato 29 maggio 2010
AJAX semplicissimo
                        class GnrCustomWebPage(object):
                            def windowTitle(self):
                                 return '!!Hello world'

                            def main(self, root, **kwargs):
                                tabber = root.tabContainer()
                                tab = tabber.contentPane(title='Tab')
                                tab.button('Che ore sono?',action='FIRE chiedi_ora;')
                                root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora')
                                tab.div('^risultato')

                            def rpc_dammi_ora(self):
                                return datetime.datetime.now()




sabato 29 maggio 2010
AJAX semplicissimo
                        class GnrCustomWebPage(object):
                            def windowTitle(self):
                                 return '!!Hello world'

                            def main(self, root, **kwargs):
                                tabber = root.tabContainer()
                                tab = tabber.contentPane(title='Tab')
                                tab.button('Che ore sono?',action='FIRE chiedi_ora;')
                                root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora')
                                tab.div('^risultato')

                            def rpc_dammi_ora(self):
                                return datetime.datetime.now()




sabato 29 maggio 2010
sabato 29 maggio 2010
Package(s)




sabato 29 maggio 2010
Istanze

                Package(s)




sabato 29 maggio 2010
Siti

                   Istanze

                Package(s)




sabato 29 maggio 2010
Siti     GUI

                   Istanze     Database

                Package(s)     Risorse




sabato 29 maggio 2010
Mixin


                        Siti             GUI

                   Istanze             Database

                Package(s)             Risorse




sabato 29 maggio 2010
Mixin


                        Siti
                         class GnrCustomWebPage(object):
                             def windowTitle(self):                                     GUI
                                  return '!!Hello world'

                               def main(self, root, **kwargs):

                   Istanze         tabber = root.tabContainer()
                                   tab = tabber.contentPane(title='Tab')            Database
                                   tab.button('Che ore sono?',action='FIRE chiedi_ora;')
                                   root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora')
                                   tab.div('^risultato')

                Package(s)
                      def rpc_dammi_ora(self):                                        Risorse
                                   return datetime.datetime.now()




sabato 29 maggio 2010
Mixin


                        Siti
                         class GnrCustomWebPage(object):
                             def windowTitle(self):                                     GUI
                                  return '!!Hello world'

                               def main(self, root, **kwargs):

                   Istanze         tabber = root.tabContainer()
                                   tab = tabber.contentPane(title='Tab')            Database
                                   tab.button('Che ore sono?',action='FIRE chiedi_ora;')
                                   root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora')
                                   tab.div('^risultato')

                Package(s)
                      def rpc_dammi_ora(self):
                      def rpc_dammi_ora(self):
                                                                                      Risorse
                                  return datetime.datetime.now()
                                  return Bag('http://www.example.com/websvc/get_time')['Europe.Rome']




sabato 29 maggio 2010
Stampe



sabato 29 maggio 2010
sabato 29 maggio 2010
Codice


sabato 29 maggio 2010
Codice   Editor PDF


sabato 29 maggio 2010
Il progetto
                           atto II


sabato 29 maggio 2010
Inserimento dati
                                 tramite form Web




                                                      Inserimento dati
                                                     tramite form PDF
                         User
                        Utente



                                      Stampa ed
                                     archiviazione




sabato 29 maggio 2010
sabato 29 maggio 2010
GUI comune                      form richiesta

                                                       formato dati PDF
                         fascicolo.py
                                                       m4.py (mixin)
                          (webpage)
                                                        azioni pre / post
                        communicazione
                           con PDF




                                                         elementi GUI
                                         Componenti
                                                      condivisi nelle forms




sabato 29 maggio 2010
Tabella “documento”

        class Table(object):

            def config_db(self, pkg):
                tbl = pkg.table('documento', pkey='id',name_long='!!Documento',
        name_plural='!!Documenti', rowcaption="$descrizione")
                self.sysAndComuneIdFields(tbl)
                tbl.column('fascicolo',name_long='!!Fascicolo')
                tbl.column('modello',name_long='!!Modello')
                tbl.column('data','D',name_long='!!Data del documento')
                tbl.column('ts_richiesta','DH',name_long='!!Data e ora')
                tbl.column('dati_richiesta','X',group='_',name_long='!!Dati richiesta',
        _sendback=True)
                tbl.column('dati_pdf','X',group='_',name_long='!!Dati del documento PDF')
                tbl.column('descrizione',name_long='!!Descrizione')

                tbl.column('user_id',size='22',group='_', _sendback=True).relation
        ('adm.user.id',mode='foreignkey',onDelete='cascade',deferred=True, one_one=True)




sabato 29 maggio 2010
Tabella “documento”

        class Table(object):

            def config_db(self, pkg):
                tbl = pkg.table('documento', pkey='id',name_long='!!Documento',
        name_plural='!!Documenti', rowcaption="$descrizione")
                self.sysAndComuneIdFields(tbl)
                tbl.column('fascicolo',name_long='!!Fascicolo')
                tbl.column('modello',name_long='!!Modello')
                tbl.column('data','D',name_long='!!Data del documento')
                tbl.column('ts_richiesta','DH',name_long='!!Data e ora')
                tbl.column('dati_richiesta','X',group='_',name_long='!!Dati richiesta',
        _sendback=True)
                tbl.column('dati_pdf','X',group='_',name_long='!!Dati del documento PDF')
                tbl.column('descrizione',name_long='!!Descrizione')

                tbl.column('user_id',size='22',group='_', _sendback=True).relation
        ('adm.user.id',mode='foreignkey',onDelete='cascade',deferred=True, one_one=True)




sabato 29 maggio 2010
Tabella “documento”

        class Table(object):

            def config_db(self, pkg):
                tbl = pkg.table('documento', pkey='id',name_long='!!Documento',
        name_plural='!!Documenti', rowcaption="$descrizione")
                self.sysAndComuneIdFields(tbl)
                tbl.column('fascicolo',name_long='!!Fascicolo')
                tbl.column('modello',name_long='!!Modello')
                tbl.column('data','D',name_long='!!Data del documento')
                tbl.column('ts_richiesta','DH',name_long='!!Data e ora')
                tbl.column('dati_richiesta','X',group='_',name_long='!!Dati richiesta',
        _sendback=True)
                tbl.column('dati_pdf','X',group='_',name_long='!!Dati del documento PDF')
                tbl.column('descrizione',name_long='!!Descrizione')

                tbl.column('user_id',size='22',group='_', _sendback=True).relation
        ('adm.user.id',mode='foreignkey',onDelete='cascade',deferred=True, one_one=True)




sabato 29 maggio 2010
Componenti
                   class Personale(BaseComponent):

                        py_requires="elezforms:BaseElezForms"

                        def formPersonale(self, pane, **base_kwargs):
                            kwargs = {'width': '100%', 'border_spacing': '4px'}
                            kwargs.update(base_kwargs)
                            fb = pane.formbuilder(cols=2, dbtable="comune.personale", **kwargs)
                            fb.field('num')
                            fb.field('nominativo', autospan=1)
                            fb.field('data_nas', autospan=1)
                            fb.field('qualifica', autospan=1)
                            fb.field('categoria', autospan=1)
                            fb.field('ufficio', autospan=1)
                            fb.field('num_ore', autospan=1)
                            fb.field('incarico', autospan=1)
                            return fb




sabato 29 maggio 2010
Componenti
                   class Personale(BaseComponent):

                        # ... continua ...

                        def selezionaMoltiPersonale(self, parentBC, **base_kwargs):
                            kwargs = dict(
                                label="Personale",
                                basename="personale",
                                table="comune.personale",
                                selectionPars=dict(order_by="nominativo"))
                            kwargs.update(base_kwargs)
                            self.selezionaMolti(parentBC, **kwargs)

                        def personale_struct(self, struct):
                            r = struct.view().rows()
                            r.fieldcell("num", width="4em")
                            r.fieldcell("nominativo", width="15em")
                            r.fieldcell("data_nas", width="8em", format_fullYear=True)
                            r.fieldcell("categoria", width="10em")
                            r.fieldcell("ufficio", width="15em")
                            return struct




sabato 29 maggio 2010
Mixin
            class Modulo(object):

                 def windowTitle(self):
                     return '!!1/4. Nomina messi notificatori straordinari'

                 def fascicolo(self):
                     return 'f1'

                 def modelli(self):
                     return [('1_4', '1/4. Nomina messi notificatori straordinari')]

                 def abilitaCompilazioneGuidata(self):
                     return True

                 def enableSaveDatiPdf(self):
                     return False

                 def div_toolbar(self, div):
                     div.button("Personale", connect_onclick="genro.gotoURL('/comune/personale')")

                 def form_NuovaRichiesta(self, parentBC,**kwargs):
                     bc = parentBC.borderContainer(**kwargs)
                     self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id", label="Seleziona i messi notificatori")

                 def formatoDatiPdf(self, root):
                     root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id in :personale_id',
                                                                 personale_id="=dati_richiesta.personale_id",
                                                                 multiple=True))




sabato 29 maggio 2010
Mixin
            class Modulo(object):

                 def windowTitle(self):
                     return '!!1/4. Nomina messi notificatori straordinari'

                 def fascicolo(self):
                     return 'f1'

                 def modelli(self):
                     return [('1_4', '1/4. Nomina messi notificatori straordinari')]
       def form_NuovaRichiesta(self, parentBC,**kwargs):
             def bc = parentBC.borderContainer(**kwargs)
                 abilitaCompilazioneGuidata(self):
                 return True
                 self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id",
       label="Seleziona i messi notificatori")
             def enableSaveDatiPdf(self):
                        return False

                 def div_toolbar(self, div):
                     div.button("Personale", connect_onclick="genro.gotoURL('/comune/personale')")

                 def form_NuovaRichiesta(self, parentBC,**kwargs):
                     bc = parentBC.borderContainer(**kwargs)
                     self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id", label="Seleziona i messi notificatori")

                 def formatoDatiPdf(self, root):
                     root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id in :personale_id',
                                                                 personale_id="=dati_richiesta.personale_id",
                                                                 multiple=True))




sabato 29 maggio 2010
Mixin
            class Modulo(object):

                 def windowTitle(self):
                     return '!!1/4. Nomina messi notificatori straordinari'

                 def fascicolo(self):
                     return 'f1'

                 def modelli(self):
                     return [('1_4', '1/4. Nomina messi notificatori straordinari')]
       def formatoDatiPdf(self, root):
             def root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id
                 abilitaCompilazioneGuidata(self):
                 return True
       in :personale_id', personale_id="=dati_richiesta.personale_id",multiple=True))
                 def enableSaveDatiPdf(self):
                     return False

                 def div_toolbar(self, div):
                     div.button("Personale", connect_onclick="genro.gotoURL('/comune/personale')")

                 def form_NuovaRichiesta(self, parentBC,**kwargs):
                     bc = parentBC.borderContainer(**kwargs)
                     self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id", label="Seleziona i messi notificatori")

                 def formatoDatiPdf(self, root):
                     root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id in :personale_id',
                                                                 personale_id="=dati_richiesta.personale_id",
                                                                 multiple=True))




sabato 29 maggio 2010
Mixin
            class Modulo(object):

                 def windowTitle(self):
                     return '!!1/4. Nomina messi notificatori straordinari'

                 def fascicolo(self):
                     return 'f1'

                 def modelli(self):
                     return [('1_4', '1/4. Nomina messi notificatori straordinari')]

                 def abilitaCompilazioneGuidata(self):
                     return True

                 def enableSaveDatiPdf(self):
                     return False

                 def div_toolbar(self, div):
                     div.button("Personale", connect_onclick="genro.gotoURL('/comune/personale')")

                 def form_NuovaRichiesta(self, parentBC,**kwargs):
                     bc = parentBC.borderContainer(**kwargs)
                     self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id", label="Seleziona i messi notificatori")

                 def formatoDatiPdf(self, root):
                     root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id in :personale_id',
                                                                 personale_id="=dati_richiesta.personale_id",
                                                                 multiple=True))




sabato 29 maggio 2010
Mixin
            class Modulo(object):

                 def windowTitle(self):
                     return '!!1/4. Nomina messi notificatori straordinari'

              def fascicolo(self):
    def    form_NuovaRichiesta(self,
                  return 'f1'                   parentBC,**kwargs):
           bc = parentBC.borderContainer(**kwargs)
              def modelli(self):
           self.selezionaSezione(bc, messi notificatori straordinari')]
                  return [('1_4', '1/4. Nomina storeRecord="#dati_richiesta.sezione",

              def abilitaCompilazioneGuidata(self): sezione")
                     label="Seleziona la
                        return True

    def formatoDatiPdf(self, root):
           def enableSaveDatiPdf(self):
        sez = return False
               root.sezione(onLoad=self.creaRecord(datapath='dati_richiesta.sezione'))
        sez.attestazione(onLoad=self.selezionaRecord(
           def div_toolbar(self, div):
               div.button("Personale", connect_onclick="genro.gotoURL('/comune/personale')")
    where='$comune_id = :comune_id and $sezione_id = :sezione_id and not fuori_comune',
           def form_NuovaRichiesta(self, parentBC,**kwargs):              sezione_id='=parent.id',
               bc = parentBC.borderContainer(**kwargs)
                                                                          order_by='$sesso,$nominativo',
               self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id", label="Seleziona i messi notificatori")
                                                                          multiple=True))
                 def formatoDatiPdf(self, root):
                     root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id in :personale_id',
                                                                 personale_id="=dati_richiesta.personale_id",
                                                                 multiple=True))




sabato 29 maggio 2010
RSS Reader
sabato 29 maggio 2010
def feedform(self,pane):
                                                                                                                      fb = pane.formbuilder(cols=2,border_spacing='4px',datapath='.record',formId='rss',
                                                                                                                                          controllerPath='form',pkeyPath='feed.curr.pkey',
                                                                                                                                          width='90%',dbtable='rss.feed')
                                                                                                                      #fb.textbox(value='^.topic',lbl='!!Topic',width='100%')



                                  RSS Reader
                                                                                                                      #fb.textbox(value='^.title',lbl='!!Title',width='100%')
                                                                                                                      #fb.textbox(value='^.url',lbl='!!Address',colspan='2',width='100%')
                                                                                                                      fb.field('topic',autospan=1)
                                                                                                                      fb.field('title',autospan=1)
                                                                                                                      fb.field('url',autospan=2)

                                                                                                                      fb.button('!!Save',action="genro.formById('rss').save();",
                                                                                                                                  disabled='==!_valid',_valid='^form.valid')



                                       109 righe
                                                                                                                      fb.button('!!New',action="FIRE feed.curr.pkey='*newrecord*';")

                                                                                                                      # == ritorna un espressione javascript
                                                                                                                      pane.dataController("""
                                                                                                                                          genro.formById('rss').load({destPkey:destPkey});""",
                                                                                                                                          destPkey='^.curr.pkey',_onStart=True)

                                                                                                                      pane.dataRpc('.savedId','saveFeed',record='=.record',
                                                                                                                                  _onResult="""
                                                                                                                                              genro.formById('rss').saved();
                                                                                                                                              FIRE .refresh;""",nodeId='rss_saver')
                                                                                                                      pane.dataRecord('.record','rss.feed',pkey='=.curr.pkey',nodeId='rss_loader',
    #!/usr/bin/env pythonw                                                                                                            _onResult="genro.formById('rss').loaded()")
    # -*- coding: UTF-8 -*-
    #                                                                                                             def rpc_saveFeed(self,record=None,**kwargs):
    # untitled                                                                                                        tblfeed = self.db.table(self.maintable)
    #                                                                                                                 if not record['id']:
    # Created by Giovanni Porcari on 2007-03-24.                                                                          record['username'] = self.user
    # Copyright (c) 2007 Softwell. All rights reserved.                                                                   tblfeed.insert(record)
    #                                                                                                                 else:
                                                                                                                          tblfeed.update(record)
    """ RSS READER """                                                                                                self.db.commit()
    from gnr.core.gnrbag import Bag                                                                                   return record['id']

    class GnrCustomWebPage(object):                                                                               def rpc_getFeeds(self):
        maintable='rss.feed'                                                                                          results = self.db.table(self.maintable).getFeeds(user = self.user)
        css_require='rssreader'                                                                                       return results

       def pageAuthTags(self, **kwargs):                                                                           def rpc_getItems(self,url=None,**kwargs):
           return 'user'                                                                                               rss=Bag(url)['rss.channel'].digest('#v')
                                                                                                                       rows = Bag()
       def main(self, root, **kwargs):                                                                                 for i,item in enumerate(rss):
           layout = root.borderContainer(design="sidebar")                                                                 if isinstance(item,Bag):
           self.left(layout.borderContainer(region='left', width="30%", splitter=True,                                         rows.setItem('n_%i' %i,None,title=item['title'],link=item
                                             _class='fakeclass',datapath='feed'))                              ['link'],description=item['description'])
           self.top(layout.contentPane(region='top',height='30%', splitter=True,_class='fakeclass'))                   return rows
           center = layout.stackContainer(region='center',_class='fakeclass',selectedPage='^rss.page')
           center.contentPane(pageName='loading').div('...Loading...')
           center.contentPane(pageName='loaded').iframe(height='100%',width='100%',                               def item_struct(self):
                                                       delay=2000,border='0',                                         struct = self.newGridStruct()
                                                       onUpdating='genro.setData("rss.page","loading");',             r = struct.view().rows()
                                                       onLoad='genro.setData("rss.page","loaded");',                  r.cell('title', name='!!Title', width='20em',classes='titleCell')
                                                       src='^rss.link')                                               r.cell('description', name='!!Description', width='50em',classes='descCell')
                                                                                                                      return struct
       def left(self,bc):
           self.feedform(bc.contentPane(region='top',_class='fakeclass'))
           center = bc.contentPane(region='center',_class='fakeclass')                                            def top(self,pane):
           center.tree(storepath='.tree',labelAttribute='caption',selected_k_id='.curr.pkey',                         pane.includedView(storepath='rss.rows',
                       selected_k_url='.curr.url',_fired='^.refreshTree', inspect='shift')                                              nodeId='rssItemsGrid',autoWidth=True,
           center.dataRpc('.tree','getFeeds',_fired='^.refresh',_onResult='FIRE .refreshTree',_onStart=True)                            selected_link='rss.link',
           center.dataRpc('rss.rows','getItems',url='^.curr.url',_if='url',_else="null")                                                struct=self.item_struct())




sabato 29 maggio 2010
Presente   Futuro



sabato 29 maggio 2010
Community,
                        Community,
                        Community


                                     Futuro



sabato 29 maggio 2010
Grazie!


                                                             Roberto Lupi
                        GenroPy                              @robertolupi
                        http://www.genropy.org/              roberto@lupi.an.it
                                                             http://www.medmediagroup.it/
                        http://svn.genropy.org/genro/trunk
                                                             http://blog.lupi-software.com/



sabato 29 maggio 2010

Más contenido relacionado

Más de PyCon Italia

Python in the browser
Python in the browserPython in the browser
Python in the browserPyCon Italia
 
PyPy 1.2: snakes never crawled so fast
PyPy 1.2: snakes never crawled so fastPyPy 1.2: snakes never crawled so fast
PyPy 1.2: snakes never crawled so fastPyCon Italia
 
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni python
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni pythonPyCuda: Come sfruttare la potenza delle schede video nelle applicazioni python
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni pythonPyCon Italia
 
OpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con PythonOpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con PythonPyCon Italia
 
New and improved: Coming changes to the unittest module
 	 New and improved: Coming changes to the unittest module 	 New and improved: Coming changes to the unittest module
New and improved: Coming changes to the unittest modulePyCon Italia
 
Monitoraggio del Traffico di Rete Usando Python ed ntop
Monitoraggio del Traffico di Rete Usando Python ed ntopMonitoraggio del Traffico di Rete Usando Python ed ntop
Monitoraggio del Traffico di Rete Usando Python ed ntopPyCon Italia
 
Jython for embedded software validation
Jython for embedded software validationJython for embedded software validation
Jython for embedded software validationPyCon Italia
 
Foxgame introduzione all'apprendimento automatico
Foxgame introduzione all'apprendimento automaticoFoxgame introduzione all'apprendimento automatico
Foxgame introduzione all'apprendimento automaticoPyCon Italia
 
Django è pronto per l'Enterprise
Django è pronto per l'EnterpriseDjango è pronto per l'Enterprise
Django è pronto per l'EnterprisePyCon Italia
 
Crogioli, alambicchi e beute: dove mettere i vostri dati.
Crogioli, alambicchi e beute: dove mettere i vostri dati.Crogioli, alambicchi e beute: dove mettere i vostri dati.
Crogioli, alambicchi e beute: dove mettere i vostri dati.PyCon Italia
 
Comet web applications with Python, Django & Orbited
Comet web applications with Python, Django & OrbitedComet web applications with Python, Django & Orbited
Comet web applications with Python, Django & OrbitedPyCon Italia
 
Cleanup and new optimizations in WPython 1.1
Cleanup and new optimizations in WPython 1.1Cleanup and new optimizations in WPython 1.1
Cleanup and new optimizations in WPython 1.1PyCon Italia
 

Más de PyCon Italia (14)

Python idiomatico
Python idiomaticoPython idiomatico
Python idiomatico
 
Python in the browser
Python in the browserPython in the browser
Python in the browser
 
PyPy 1.2: snakes never crawled so fast
PyPy 1.2: snakes never crawled so fastPyPy 1.2: snakes never crawled so fast
PyPy 1.2: snakes never crawled so fast
 
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni python
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni pythonPyCuda: Come sfruttare la potenza delle schede video nelle applicazioni python
PyCuda: Come sfruttare la potenza delle schede video nelle applicazioni python
 
OpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con PythonOpenERP e l'arte della gestione aziendale con Python
OpenERP e l'arte della gestione aziendale con Python
 
New and improved: Coming changes to the unittest module
 	 New and improved: Coming changes to the unittest module 	 New and improved: Coming changes to the unittest module
New and improved: Coming changes to the unittest module
 
Monitoraggio del Traffico di Rete Usando Python ed ntop
Monitoraggio del Traffico di Rete Usando Python ed ntopMonitoraggio del Traffico di Rete Usando Python ed ntop
Monitoraggio del Traffico di Rete Usando Python ed ntop
 
Jython for embedded software validation
Jython for embedded software validationJython for embedded software validation
Jython for embedded software validation
 
Foxgame introduzione all'apprendimento automatico
Foxgame introduzione all'apprendimento automaticoFoxgame introduzione all'apprendimento automatico
Foxgame introduzione all'apprendimento automatico
 
Effective EC2
Effective EC2Effective EC2
Effective EC2
 
Django è pronto per l'Enterprise
Django è pronto per l'EnterpriseDjango è pronto per l'Enterprise
Django è pronto per l'Enterprise
 
Crogioli, alambicchi e beute: dove mettere i vostri dati.
Crogioli, alambicchi e beute: dove mettere i vostri dati.Crogioli, alambicchi e beute: dove mettere i vostri dati.
Crogioli, alambicchi e beute: dove mettere i vostri dati.
 
Comet web applications with Python, Django & Orbited
Comet web applications with Python, Django & OrbitedComet web applications with Python, Django & Orbited
Comet web applications with Python, Django & Orbited
 
Cleanup and new optimizations in WPython 1.1
Cleanup and new optimizations in WPython 1.1Cleanup and new optimizations in WPython 1.1
Cleanup and new optimizations in WPython 1.1
 

GenroPy, un framework innovativo per applicazioni web AJAX

  • 1. Un progetto in GenroPy Framework tutto italiano per applicazioni web e AJAX sabato 29 maggio 2010
  • 2. Un progetto in GenroPy Framework tutto italiano per applicazioni web e AJAX stionali ge sabato 29 maggio 2010
  • 3. Roberto Lupi @robertolupi • 10 anni di esperienza web • enterprise e intranet • Clienti: Amadori, Merloni, 21 banche • Italia e India • oggi: direttore tecnico di MedMedia software per la sanità • http://www.medmediagroup.it/ sabato 29 maggio 2010
  • 5. X M L O Web AJAX Base / dati R Business logic M PDF J S O N ! Object-relational ! domain objects / GUI RDBMS impedance mismatch domain objects impedance mismatch vs. objects vs. GUI sabato 29 maggio 2010
  • 6. HTML sabato 29 maggio 2010
  • 9. La storia sabato 29 maggio 2010
  • 11. Il progetto sabato 29 maggio 2010
  • 12. Il progetto 15 processi amministrativi sabato 29 maggio 2010
  • 13. Il progetto 15 processi 200+ forms amministrativi Web sabato 29 maggio 2010
  • 14. Il progetto 15 processi 200+ forms 190 reports e amministrativi Web forms PDF sabato 29 maggio 2010
  • 15. Il progetto 15 processi 200+ forms 190 reports e amministrativi Web forms PDF sabato 29 maggio 2010
  • 18. 2 sviluppatori 2 designers sabato 29 maggio 2010
  • 19. 2 sviluppatori 2 designers 2 mesi sabato 29 maggio 2010
  • 24. valori ed attributi simile a XML gerarchica ed ordinata Bags sabato 29 maggio 2010
  • 25. valori ed attributi simile a XML gerarchica ed ordinata Bags observer pattern dinamica lazy loading sabato 29 maggio 2010
  • 26. valori ed attributi simile a XML gerarchica ed ordinata Bags observer pattern web services database dinamica versatile lazy loading files XML directory trees sabato 29 maggio 2010
  • 27. domain specific valori ed attributi base dati languages simile a XML universale gerarchica ed ordinata interfaccia utente Bags observer pattern web services database dinamica versatile lazy loading files XML directory trees sabato 29 maggio 2010
  • 28. X M L O Business Web AJAX Base / dati R Bags M Logic PDF J S O N sabato 29 maggio 2010
  • 30. Quasi un ORM... class Table(object): def config_db(self, pkg): tbl = pkg.table('user', pkey='id', name_long='!!User', rowcaption='username,email:%s (%s)') self.sysFields(tbl,ins=True, upd=True, md5=True) tbl.column('id',size='22',group='_',readOnly='y',name_long='Id') tbl.column('username', size=':32',name_long='!!Username', unique='y', _sendback=True, indexed='y',validate_notnull=True,validate_notnull_error='!!Mandatory field') tbl.column('email',name_long='Email',validate_notnull=True, validate_notnull_error='!!Mandatory field') tbl.column('firstname', size=':32',name_long='!!First name', validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field') tbl.column('lastname', size=':32',name_long='!!Last name', validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field') tbl.column('registration_date', 'D' ,name_long='!!Registration Date') tbl.column('auth_tags', name_long='!!Authorization Tags') tbl.column('status', name_long='!!Status', size='4', validate_values_conf='!!Confirmed', validate_values_wait='!!Waiting') tbl.column('md5pwd', name_long='!!PasswordMD5', size=':65') tbl.column('locale', name_long='!!Default Language', size=':12') tbl.column('preferences', dtype='X', name_long='!!Preferences') tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name') # ... metodi d'utilità ... def trigger_onUpdating(self, record,**kwargs): # ... def trigger_onInserting(self, record,**kwargs): # ... sabato 29 maggio 2010
  • 31. Quasi un ORM... class Table(object): def config_db(self, pkg): tbl = pkg.table('user', pkey='id', name_long='!!User', rowcaption='username,email:%s (%s)') self.sysFields(tbl,ins=True, upd=True, md5=True) tbl.column('id',size='22',group='_',readOnly='y',name_long='Id') tbl.column('username', size=':32',name_long='!!Username', unique='y', _sendback=True, indexed='y',validate_notnull=True,validate_notnull_error='!!Mandatory field') tbl.column('email',name_long='Email',validate_notnull=True, validate_notnull_error='!!Mandatory field') tbl.column('firstname', size=':32',name_long='!!First name', validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field') tbl.column('lastname', size=':32',name_long='!!Last name', validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field') tbl.column('registration_date', 'D' ,name_long='!!Registration Date') tbl.column('id',size='22',group='_',readOnly='y',name_long='Id') tbl.column('auth_tags', name_long='!!Authorization Tags') tbl.column('status', name_long='!!Status', size='4', validate_values_conf='!!Confirmed', validate_values_wait='!!Waiting') tbl.column('md5pwd', name_long='!!PasswordMD5', size=':65') tbl.column('locale', name_long='!!Default Language', size=':12') tbl.column('preferences', dtype='X', name_long='!!Preferences') tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name') # ... metodi d'utilità ... def trigger_onUpdating(self, record,**kwargs): # ... def trigger_onInserting(self, record,**kwargs): # ... sabato 29 maggio 2010
  • 32. Quasi un ORM... class Table(object): def config_db(self, pkg): tbl = pkg.table('user', pkey='id', name_long='!!User', rowcaption='username,email:%s (%s)') self.sysFields(tbl,ins=True, upd=True, md5=True) tbl.column('id',size='22',group='_',readOnly='y',name_long='Id') tbl.column('username', size=':32',name_long='!!Username', unique='y', _sendback=True, indexed='y',validate_notnull=True,validate_notnull_error='!!Mandatory field') tbl.column('email',name_long='Email',validate_notnull=True, validate_notnull_error='!!Mandatory field') tbl.column('firstname', size=':32',name_long='!!First name', validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field') tbl.column('lastname', size=':32',name_long='!!Last name', validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field') tbl.column('registration_date', 'D' ,name_long='!!Registration Date') validate_notnull=True,validate_notnull_error='!!Mandatory field' tbl.column('auth_tags', name_long='!!Authorization Tags') tbl.column('status', name_long='!!Status', size='4', validate_values_conf='!!Confirmed', validate_values_wait='!!Waiting') tbl.column('md5pwd', name_long='!!PasswordMD5', size=':65') tbl.column('locale', name_long='!!Default Language', size=':12') tbl.column('preferences', dtype='X', name_long='!!Preferences') tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name') # ... metodi d'utilità ... def trigger_onUpdating(self, record,**kwargs): # ... def trigger_onInserting(self, record,**kwargs): # ... sabato 29 maggio 2010
  • 33. Quasi un ORM... class Table(object): def config_db(self, pkg): tbl = pkg.table('user', pkey='id', name_long='!!User', rowcaption='username,email:%s (%s)') self.sysFields(tbl,ins=True, upd=True, md5=True) tbl.column('id',size='22',group='_',readOnly='y',name_long='Id') tbl.column('username', size=':32',name_long='!!Username', unique='y', _sendback=True, indexed='y',validate_notnull=True,validate_notnull_error='!!Mandatory field') tbl.column('email',name_long='Email',validate_notnull=True, validate_notnull_error='!!Mandatory field') tbl.column('firstname', size=':32',name_long='!!First name', validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field') tbl.column('lastname', size=':32',name_long='!!Last name', validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field') tbl.column('registration_date', 'D' ,name_long='!!Registration Date') tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name') tbl.column('auth_tags', name_long='!!Authorization Tags') tbl.column('status', name_long='!!Status', size='4', validate_values_conf='!!Confirmed', validate_values_wait='!!Waiting') tbl.column('md5pwd', name_long='!!PasswordMD5', size=':65') tbl.column('locale', name_long='!!Default Language', size=':12') tbl.column('preferences', dtype='X', name_long='!!Preferences') tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name') # ... metodi d'utilità ... def trigger_onUpdating(self, record,**kwargs): # ... def trigger_onInserting(self, record,**kwargs): # ... sabato 29 maggio 2010
  • 34. Quasi un ORM... class Table(object): def config_db(self, pkg): tbl = pkg.table('user', pkey='id', name_long='!!User', rowcaption='username,email:%s (%s)') self.sysFields(tbl,ins=True, upd=True, md5=True) tbl.column('id',size='22',group='_',readOnly='y',name_long='Id') tbl.column('username', size=':32',name_long='!!Username', unique='y', _sendback=True, indexed='y',validate_notnull=True,validate_notnull_error='!!Mandatory field') tbl.column('email',name_long='Email',validate_notnull=True, validate_notnull_error='!!Mandatory field') tbl.column('firstname', size=':32',name_long='!!First name', validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field') tbl.column('lastname', size=':32',name_long='!!Last name', def trigger_onUpdating(self, record,**kwargs): validate_notnull=True,validate_case='c',validate_notnull_error='!!Mandatory field') # ... tbl.column('registration_date', 'D' ,name_long='!!Registration Date') tbl.column('auth_tags', name_long='!!Authorization Tags') tbl.column('status', name_long='!!Status', size='4', def trigger_onInserting(self, record,**kwargs): validate_values_conf='!!Confirmed', # ... validate_values_wait='!!Waiting') tbl.column('md5pwd', name_long='!!PasswordMD5', size=':65') tbl.column('locale', name_long='!!Default Language', size=':12') tbl.column('preferences', dtype='X', name_long='!!Preferences') tbl.formulaColumn('fullname', "firstname||' '||lastname", name_long=u'!!Name') # ... metodi d'utilità ... def trigger_onUpdating(self, record,**kwargs): # ... def trigger_onInserting(self, record,**kwargs): # ... sabato 29 maggio 2010
  • 36. HTML sabato 29 maggio 2010
  • 38. AJAX semplicissimo class GnrCustomWebPage(object): def windowTitle(self): return '!!Hello world' def main(self, root, **kwargs): tabber = root.tabContainer() tab = tabber.contentPane(title='Tab') tab.button('Che ore sono?',action='FIRE chiedi_ora;') root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora') tab.div('^risultato') def rpc_dammi_ora(self): return datetime.datetime.now() sabato 29 maggio 2010
  • 39. AJAX semplicissimo class GnrCustomWebPage(object): def windowTitle(self): return '!!Hello world' def main(self, root, **kwargs): tabber = root.tabContainer() tab = tabber.contentPane(title='Tab') tab.button('Che ore sono?',action='FIRE chiedi_ora;') root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora') tab.div('^risultato') def rpc_dammi_ora(self): return datetime.datetime.now() sabato 29 maggio 2010
  • 40. AJAX semplicissimo class GnrCustomWebPage(object): def windowTitle(self): return '!!Hello world' def main(self, root, **kwargs): tabber = root.tabContainer() tab = tabber.contentPane(title='Tab') tab.button('Che ore sono?',action='FIRE chiedi_ora;') root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora') tab.div('^risultato') def rpc_dammi_ora(self): return datetime.datetime.now() sabato 29 maggio 2010
  • 41. AJAX semplicissimo class GnrCustomWebPage(object): def windowTitle(self): return '!!Hello world' def main(self, root, **kwargs): tabber = root.tabContainer() tab = tabber.contentPane(title='Tab') tab.button('Che ore sono?',action='FIRE chiedi_ora;') root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora') tab.div('^risultato') def rpc_dammi_ora(self): return datetime.datetime.now() sabato 29 maggio 2010
  • 42. AJAX semplicissimo class GnrCustomWebPage(object): def windowTitle(self): return '!!Hello world' def main(self, root, **kwargs): tabber = root.tabContainer() tab = tabber.contentPane(title='Tab') tab.button('Che ore sono?',action='FIRE chiedi_ora;') root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora') tab.div('^risultato') def rpc_dammi_ora(self): return datetime.datetime.now() sabato 29 maggio 2010
  • 43. AJAX semplicissimo class GnrCustomWebPage(object): def windowTitle(self): return '!!Hello world' def main(self, root, **kwargs): tabber = root.tabContainer() tab = tabber.contentPane(title='Tab') tab.button('Che ore sono?',action='FIRE chiedi_ora;') root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora') tab.div('^risultato') def rpc_dammi_ora(self): return datetime.datetime.now() sabato 29 maggio 2010
  • 44. AJAX semplicissimo class GnrCustomWebPage(object): def windowTitle(self): return '!!Hello world' def main(self, root, **kwargs): tabber = root.tabContainer() tab = tabber.contentPane(title='Tab') tab.button('Che ore sono?',action='FIRE chiedi_ora;') root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora') tab.div('^risultato') def rpc_dammi_ora(self): return datetime.datetime.now() sabato 29 maggio 2010
  • 45. AJAX semplicissimo class GnrCustomWebPage(object): def windowTitle(self): return '!!Hello world' def main(self, root, **kwargs): tabber = root.tabContainer() tab = tabber.contentPane(title='Tab') tab.button('Che ore sono?',action='FIRE chiedi_ora;') root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora') tab.div('^risultato') def rpc_dammi_ora(self): return datetime.datetime.now() sabato 29 maggio 2010
  • 48. Istanze Package(s) sabato 29 maggio 2010
  • 49. Siti Istanze Package(s) sabato 29 maggio 2010
  • 50. Siti GUI Istanze Database Package(s) Risorse sabato 29 maggio 2010
  • 51. Mixin Siti GUI Istanze Database Package(s) Risorse sabato 29 maggio 2010
  • 52. Mixin Siti class GnrCustomWebPage(object): def windowTitle(self): GUI return '!!Hello world' def main(self, root, **kwargs): Istanze tabber = root.tabContainer() tab = tabber.contentPane(title='Tab') Database tab.button('Che ore sono?',action='FIRE chiedi_ora;') root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora') tab.div('^risultato') Package(s) def rpc_dammi_ora(self): Risorse return datetime.datetime.now() sabato 29 maggio 2010
  • 53. Mixin Siti class GnrCustomWebPage(object): def windowTitle(self): GUI return '!!Hello world' def main(self, root, **kwargs): Istanze tabber = root.tabContainer() tab = tabber.contentPane(title='Tab') Database tab.button('Che ore sono?',action='FIRE chiedi_ora;') root.dataRpc('risultato','dammi_ora',_fired='^chiedi_ora') tab.div('^risultato') Package(s) def rpc_dammi_ora(self): def rpc_dammi_ora(self): Risorse return datetime.datetime.now() return Bag('http://www.example.com/websvc/get_time')['Europe.Rome'] sabato 29 maggio 2010
  • 57. Codice Editor PDF sabato 29 maggio 2010
  • 58. Il progetto atto II sabato 29 maggio 2010
  • 59. Inserimento dati tramite form Web Inserimento dati tramite form PDF User Utente Stampa ed archiviazione sabato 29 maggio 2010
  • 61. GUI comune form richiesta formato dati PDF fascicolo.py m4.py (mixin) (webpage) azioni pre / post communicazione con PDF elementi GUI Componenti condivisi nelle forms sabato 29 maggio 2010
  • 62. Tabella “documento” class Table(object): def config_db(self, pkg): tbl = pkg.table('documento', pkey='id',name_long='!!Documento', name_plural='!!Documenti', rowcaption="$descrizione") self.sysAndComuneIdFields(tbl) tbl.column('fascicolo',name_long='!!Fascicolo') tbl.column('modello',name_long='!!Modello') tbl.column('data','D',name_long='!!Data del documento') tbl.column('ts_richiesta','DH',name_long='!!Data e ora') tbl.column('dati_richiesta','X',group='_',name_long='!!Dati richiesta', _sendback=True) tbl.column('dati_pdf','X',group='_',name_long='!!Dati del documento PDF') tbl.column('descrizione',name_long='!!Descrizione') tbl.column('user_id',size='22',group='_', _sendback=True).relation ('adm.user.id',mode='foreignkey',onDelete='cascade',deferred=True, one_one=True) sabato 29 maggio 2010
  • 63. Tabella “documento” class Table(object): def config_db(self, pkg): tbl = pkg.table('documento', pkey='id',name_long='!!Documento', name_plural='!!Documenti', rowcaption="$descrizione") self.sysAndComuneIdFields(tbl) tbl.column('fascicolo',name_long='!!Fascicolo') tbl.column('modello',name_long='!!Modello') tbl.column('data','D',name_long='!!Data del documento') tbl.column('ts_richiesta','DH',name_long='!!Data e ora') tbl.column('dati_richiesta','X',group='_',name_long='!!Dati richiesta', _sendback=True) tbl.column('dati_pdf','X',group='_',name_long='!!Dati del documento PDF') tbl.column('descrizione',name_long='!!Descrizione') tbl.column('user_id',size='22',group='_', _sendback=True).relation ('adm.user.id',mode='foreignkey',onDelete='cascade',deferred=True, one_one=True) sabato 29 maggio 2010
  • 64. Tabella “documento” class Table(object): def config_db(self, pkg): tbl = pkg.table('documento', pkey='id',name_long='!!Documento', name_plural='!!Documenti', rowcaption="$descrizione") self.sysAndComuneIdFields(tbl) tbl.column('fascicolo',name_long='!!Fascicolo') tbl.column('modello',name_long='!!Modello') tbl.column('data','D',name_long='!!Data del documento') tbl.column('ts_richiesta','DH',name_long='!!Data e ora') tbl.column('dati_richiesta','X',group='_',name_long='!!Dati richiesta', _sendback=True) tbl.column('dati_pdf','X',group='_',name_long='!!Dati del documento PDF') tbl.column('descrizione',name_long='!!Descrizione') tbl.column('user_id',size='22',group='_', _sendback=True).relation ('adm.user.id',mode='foreignkey',onDelete='cascade',deferred=True, one_one=True) sabato 29 maggio 2010
  • 65. Componenti class Personale(BaseComponent): py_requires="elezforms:BaseElezForms" def formPersonale(self, pane, **base_kwargs): kwargs = {'width': '100%', 'border_spacing': '4px'} kwargs.update(base_kwargs) fb = pane.formbuilder(cols=2, dbtable="comune.personale", **kwargs) fb.field('num') fb.field('nominativo', autospan=1) fb.field('data_nas', autospan=1) fb.field('qualifica', autospan=1) fb.field('categoria', autospan=1) fb.field('ufficio', autospan=1) fb.field('num_ore', autospan=1) fb.field('incarico', autospan=1) return fb sabato 29 maggio 2010
  • 66. Componenti class Personale(BaseComponent): # ... continua ... def selezionaMoltiPersonale(self, parentBC, **base_kwargs): kwargs = dict( label="Personale", basename="personale", table="comune.personale", selectionPars=dict(order_by="nominativo")) kwargs.update(base_kwargs) self.selezionaMolti(parentBC, **kwargs) def personale_struct(self, struct): r = struct.view().rows() r.fieldcell("num", width="4em") r.fieldcell("nominativo", width="15em") r.fieldcell("data_nas", width="8em", format_fullYear=True) r.fieldcell("categoria", width="10em") r.fieldcell("ufficio", width="15em") return struct sabato 29 maggio 2010
  • 67. Mixin class Modulo(object): def windowTitle(self): return '!!1/4. Nomina messi notificatori straordinari' def fascicolo(self): return 'f1' def modelli(self): return [('1_4', '1/4. Nomina messi notificatori straordinari')] def abilitaCompilazioneGuidata(self): return True def enableSaveDatiPdf(self): return False def div_toolbar(self, div): div.button("Personale", connect_onclick="genro.gotoURL('/comune/personale')") def form_NuovaRichiesta(self, parentBC,**kwargs): bc = parentBC.borderContainer(**kwargs) self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id", label="Seleziona i messi notificatori") def formatoDatiPdf(self, root): root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id in :personale_id', personale_id="=dati_richiesta.personale_id", multiple=True)) sabato 29 maggio 2010
  • 68. Mixin class Modulo(object): def windowTitle(self): return '!!1/4. Nomina messi notificatori straordinari' def fascicolo(self): return 'f1' def modelli(self): return [('1_4', '1/4. Nomina messi notificatori straordinari')] def form_NuovaRichiesta(self, parentBC,**kwargs): def bc = parentBC.borderContainer(**kwargs) abilitaCompilazioneGuidata(self): return True self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id", label="Seleziona i messi notificatori") def enableSaveDatiPdf(self): return False def div_toolbar(self, div): div.button("Personale", connect_onclick="genro.gotoURL('/comune/personale')") def form_NuovaRichiesta(self, parentBC,**kwargs): bc = parentBC.borderContainer(**kwargs) self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id", label="Seleziona i messi notificatori") def formatoDatiPdf(self, root): root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id in :personale_id', personale_id="=dati_richiesta.personale_id", multiple=True)) sabato 29 maggio 2010
  • 69. Mixin class Modulo(object): def windowTitle(self): return '!!1/4. Nomina messi notificatori straordinari' def fascicolo(self): return 'f1' def modelli(self): return [('1_4', '1/4. Nomina messi notificatori straordinari')] def formatoDatiPdf(self, root): def root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id abilitaCompilazioneGuidata(self): return True in :personale_id', personale_id="=dati_richiesta.personale_id",multiple=True)) def enableSaveDatiPdf(self): return False def div_toolbar(self, div): div.button("Personale", connect_onclick="genro.gotoURL('/comune/personale')") def form_NuovaRichiesta(self, parentBC,**kwargs): bc = parentBC.borderContainer(**kwargs) self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id", label="Seleziona i messi notificatori") def formatoDatiPdf(self, root): root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id in :personale_id', personale_id="=dati_richiesta.personale_id", multiple=True)) sabato 29 maggio 2010
  • 70. Mixin class Modulo(object): def windowTitle(self): return '!!1/4. Nomina messi notificatori straordinari' def fascicolo(self): return 'f1' def modelli(self): return [('1_4', '1/4. Nomina messi notificatori straordinari')] def abilitaCompilazioneGuidata(self): return True def enableSaveDatiPdf(self): return False def div_toolbar(self, div): div.button("Personale", connect_onclick="genro.gotoURL('/comune/personale')") def form_NuovaRichiesta(self, parentBC,**kwargs): bc = parentBC.borderContainer(**kwargs) self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id", label="Seleziona i messi notificatori") def formatoDatiPdf(self, root): root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id in :personale_id', personale_id="=dati_richiesta.personale_id", multiple=True)) sabato 29 maggio 2010
  • 71. Mixin class Modulo(object): def windowTitle(self): return '!!1/4. Nomina messi notificatori straordinari' def fascicolo(self): def form_NuovaRichiesta(self, return 'f1' parentBC,**kwargs): bc = parentBC.borderContainer(**kwargs) def modelli(self): self.selezionaSezione(bc, messi notificatori straordinari')] return [('1_4', '1/4. Nomina storeRecord="#dati_richiesta.sezione", def abilitaCompilazioneGuidata(self): sezione") label="Seleziona la return True def formatoDatiPdf(self, root): def enableSaveDatiPdf(self): sez = return False root.sezione(onLoad=self.creaRecord(datapath='dati_richiesta.sezione')) sez.attestazione(onLoad=self.selezionaRecord( def div_toolbar(self, div): div.button("Personale", connect_onclick="genro.gotoURL('/comune/personale')") where='$comune_id = :comune_id and $sezione_id = :sezione_id and not fuori_comune', def form_NuovaRichiesta(self, parentBC,**kwargs): sezione_id='=parent.id', bc = parentBC.borderContainer(**kwargs) order_by='$sesso,$nominativo', self.selezionaMoltiPersonale(bc, values="#dati_richiesta.personale_id", label="Seleziona i messi notificatori") multiple=True)) def formatoDatiPdf(self, root): root.personale(onLoad=self.selezionaRecord('$comune_id = :comune_id and $id in :personale_id', personale_id="=dati_richiesta.personale_id", multiple=True)) sabato 29 maggio 2010
  • 72. RSS Reader sabato 29 maggio 2010
  • 73. def feedform(self,pane): fb = pane.formbuilder(cols=2,border_spacing='4px',datapath='.record',formId='rss', controllerPath='form',pkeyPath='feed.curr.pkey', width='90%',dbtable='rss.feed') #fb.textbox(value='^.topic',lbl='!!Topic',width='100%') RSS Reader #fb.textbox(value='^.title',lbl='!!Title',width='100%') #fb.textbox(value='^.url',lbl='!!Address',colspan='2',width='100%') fb.field('topic',autospan=1) fb.field('title',autospan=1) fb.field('url',autospan=2) fb.button('!!Save',action="genro.formById('rss').save();", disabled='==!_valid',_valid='^form.valid') 109 righe fb.button('!!New',action="FIRE feed.curr.pkey='*newrecord*';") # == ritorna un espressione javascript pane.dataController(""" genro.formById('rss').load({destPkey:destPkey});""", destPkey='^.curr.pkey',_onStart=True) pane.dataRpc('.savedId','saveFeed',record='=.record', _onResult=""" genro.formById('rss').saved(); FIRE .refresh;""",nodeId='rss_saver') pane.dataRecord('.record','rss.feed',pkey='=.curr.pkey',nodeId='rss_loader', #!/usr/bin/env pythonw _onResult="genro.formById('rss').loaded()") # -*- coding: UTF-8 -*- # def rpc_saveFeed(self,record=None,**kwargs): # untitled tblfeed = self.db.table(self.maintable) # if not record['id']: # Created by Giovanni Porcari on 2007-03-24. record['username'] = self.user # Copyright (c) 2007 Softwell. All rights reserved. tblfeed.insert(record) # else: tblfeed.update(record) """ RSS READER """ self.db.commit() from gnr.core.gnrbag import Bag return record['id'] class GnrCustomWebPage(object): def rpc_getFeeds(self): maintable='rss.feed' results = self.db.table(self.maintable).getFeeds(user = self.user) css_require='rssreader' return results def pageAuthTags(self, **kwargs): def rpc_getItems(self,url=None,**kwargs): return 'user' rss=Bag(url)['rss.channel'].digest('#v') rows = Bag() def main(self, root, **kwargs): for i,item in enumerate(rss): layout = root.borderContainer(design="sidebar") if isinstance(item,Bag): self.left(layout.borderContainer(region='left', width="30%", splitter=True, rows.setItem('n_%i' %i,None,title=item['title'],link=item _class='fakeclass',datapath='feed')) ['link'],description=item['description']) self.top(layout.contentPane(region='top',height='30%', splitter=True,_class='fakeclass')) return rows center = layout.stackContainer(region='center',_class='fakeclass',selectedPage='^rss.page') center.contentPane(pageName='loading').div('...Loading...') center.contentPane(pageName='loaded').iframe(height='100%',width='100%', def item_struct(self): delay=2000,border='0', struct = self.newGridStruct() onUpdating='genro.setData("rss.page","loading");', r = struct.view().rows() onLoad='genro.setData("rss.page","loaded");', r.cell('title', name='!!Title', width='20em',classes='titleCell') src='^rss.link') r.cell('description', name='!!Description', width='50em',classes='descCell') return struct def left(self,bc): self.feedform(bc.contentPane(region='top',_class='fakeclass')) center = bc.contentPane(region='center',_class='fakeclass') def top(self,pane): center.tree(storepath='.tree',labelAttribute='caption',selected_k_id='.curr.pkey', pane.includedView(storepath='rss.rows', selected_k_url='.curr.url',_fired='^.refreshTree', inspect='shift') nodeId='rssItemsGrid',autoWidth=True, center.dataRpc('.tree','getFeeds',_fired='^.refresh',_onResult='FIRE .refreshTree',_onStart=True) selected_link='rss.link', center.dataRpc('rss.rows','getItems',url='^.curr.url',_if='url',_else="null") struct=self.item_struct()) sabato 29 maggio 2010
  • 74. Presente Futuro sabato 29 maggio 2010
  • 75. Community, Community, Community Futuro sabato 29 maggio 2010
  • 76. Grazie! Roberto Lupi GenroPy @robertolupi http://www.genropy.org/ roberto@lupi.an.it http://www.medmediagroup.it/ http://svn.genropy.org/genro/trunk http://blog.lupi-software.com/ sabato 29 maggio 2010