Formul´ arios para Plone: um passeio pelo framework z3c.form Rud´ a Porto Filgueiras - [email protected] - @rudaporto September 29, 2011
Jul 09, 2015
Formularios para Plone: um passeio peloframework z3c.form
Ruda Porto Filgueiras - [email protected] - @rudaporto
September 29, 2011
Agenda
Introducao
Historia
z3c.form
Perguntas
Introducao
I Por que formularios sao importantes?
I Como posso simplificar a criacao de formularios?
I Como posso melhorar o reuso?
I Como os formularios podem ser mais resistentes a falhas?
CMFFormController
Recursos:
I Cola que conecta scripts com formularios e vice-versa
I Simplifica a codificacao de formularios / scripts paramanipular formularios
I Gerencia a transicao entre formularios e scripts
I Conponentes: Forms (.cpt), Validators(.vpy),Actions(Buttoes), Scritps(.cpy), State
Problemas:
I Arquivos espalhados dificultam o entendimento do fluxo
I Criacao e exibicao de widgets nao sao tratadas
I Nao funciona com ZCA packages / views
zope.formlib
Caracteristicas:
I pacote padrao do ZTK para criacao de formularios
I formularios sao um tipo de BrowserPage (context, request)
I define classes reusaveis para criacao de formularios
I possui template padrao (plone.app.form overrrides)
I permite a customizacao de widgets, actions, validators, etc
I define o padrao update() e render() ao ser invocado
Problemas:
I Nivel de customizacao e limitado para casos mais complexos
I Nao e pensado para a definicao de formularios aninhados (paie filho)
I Documentacao escassa: ”luke use de force: read the source”
z3c.form
O objetivo geral do z3c.form e tornar o desenvolvimento deformularios o mais simples possıvel e ao mesmo tempo proverhooks que permitam a customizacao dos formularios em qualquernıvel de acordo com as necessidades reais de diferentes casos deuso. Principais componentes (modulos):
form formularios base: Form, AddForm, EditForm,DisplayForm
groups formularios compostos de grupos de campos(fieldsets)
subform formularios aninhados
field API para manipulalcao dos campos do formulario
button API para manipulacao dos botoes do formulario
validator API de validacao dos dados do formulario
widget API de criacao das widgets
action API para definicao e manipulacao de actions handlers
z3c.form: processamento do formulario
Elementos principais:
self.request objeto representando a requiscao HTTP atual
self.context Item associado ao formulario de acordo com contextono qual ele foi invocado;
self.getContent() Objeto retirado do contexto e que seramanipulado pelo formulario a nao ser queignoreContext seja definido como True;
self.status A mensagem que sera exibida no topo da regiao doconteudo quando o formulario for renderizado.
updateWidgets atualiza todas as widgets de acordo com os dadosenviados
updateActions invoca os actions handlers do formulario de acordocom o botao pressionados
render invoca o template padrao que gera o HTML doformulario e retorna esse conteudo
Exemplo: Person Interface
1 import zope . i n t e r f a c e2 import zope . schema34 c l a s s IPerson ( zope . i n t e r f a c e . I n t e r f a c e ) :56 i d = zope . schema . TextLine (7 t i t l e=u ' ID ' ,8 r e a don l y=True ,9 r e q u i r e d=True )
1011 name = zope . schema . TextLine (12 t i t l e=u 'Name ' ,13 r e q u i r e d=True )1415 gender = zope . schema . Cho ice (16 t i t l e=u ' Gender ' ,17 v a l u e s=( 'male ' , ' f ema l e ' ) ,18 r e q u i r e d=Fa l se )19 ...
Exemplo: Person
1 from zope . schema . f i e l d p r o p e r t y import F i e l dP r o p e r t y23 c l a s s Person ( ob ject ) :4 zope . i n t e r f a c e . implements ( IPe r s on )56 i d = F i e l dP r o p e r t y ( IPe r s on [ ' i d ' ] )7 name = F i e l dP r o p e r t y ( IPe r s on [ 'name ' ] )8 gender = F i e l dP r o p e r t y ( IPe r s on [ ' gender ' ] )9
10 def i n i t ( s e l f , id , name , gender=None ) :11 s e l f . i d = i d12 s e l f . name = name13 i f gender :14 s e l f . gender = gender
Exemplo: PersonAddForm
1 from z3c . form import form , f i e l d23 c l a s s PersonAddForm ( form . AddForm ) :45 f i e l d s = f i e l d . F i e l d s ( IPe r s on )67 def c reate ( s e l f , data ) :8 re tu rn Person (** data )9
10 def add ( s e l f , ob ject ) :11 s e l f . c on t e x t [ ob ject . i d ] = ob ject1213 def nextURL ( s e l f ) :14 re tu rn ' i n d e x . html '
Exemplo: processamento do formulario
1 from z3c . form . t e s t i n g import TestRequest23 r e q u e s t = TestReques t ( )4 addForm = PersonAddForm ( app , r e q u e s t )5 addForm . update ( )
Nesse momento, ocorre uma seria de acoes:
I As widgets sao inicializadas de acordo com os camposdefinidos no atributo fields do formulario
I O atributo addForm.widgets e o widget manager que contemtodas as widgets inicializdas
I Porem nao sao criadas widgets para todos os campos: se odado nao estiver acessıvel no objeto ou um se houver umaconfiguracao para ignorar esse campo
Exemplo: inicializacao das widgetsVarias informacoes dos campos sao transferidas para as widgets,mas podem ser alterados posteriormente:
1 addForm . w idge t s [ ' age ' ]23 # f i e l d . t i t l e −> age . l a b e l4 age . l a b e l5 u 'Age '
67 #f i e l d . r e q u i r e d −> age . r e q u i r e d8 age . r e q u i r e d9 Fa l se
O proximo passo e determinar o valor que deve ser exibido nawidget, na seguinte ordem:
I O valor padrao definido no schema
I O valor atual do objeto que esta sendo manipulado
I O valor armazenado no request, se o formulario ainda nao foisubmetido ou ocorreu erros na validacao
Exemplo: propriedades das widgets
A propriedade mode define se a widget sera renderizada paraedicao (input) ou visualizacao (display):
1 age . mode2 ' i n pu t '
O modo da widget e inicializado seguindo a seguinte ordem (ositens posteriores sobrescrevem os anteriores):
I O valor global definido no widget manager
I A permissao do attributo do objeto que esta sendo manipulado
I A flag readonly definida no schema
I O atributo mode definido no field
Outras propriedades que podem ser customizadas na widget sao osatributos: label e required.
Exemplo: encontrar um action manager e executa-lo
O botao ”Add” e ao mesmo tempo um action e um widget:
1 l en ( addForm . a c t i o n s )2 134 addAct ion = addForm . a c t i o n s [ ' add ' ]5 addAct ion . t i t l e6 u 'Add '
78 addAct ion . v a l u e9 u 'Add '
O action handler do AddForm realiza sequencia de acoes:
I chama o metodo create(data) passando os dados enviados noformulario
I chama o metodo add(object) com o resultado do create()
I redireciona para a URL retornada pelo metodo nextURL() sefoi finalizada a criacao do novo objeto
Exemplo: form.AddForm.handleAdd
1 c l a s s AddForm(Form ) :2 ”””A f i e l d and button based add form . ”””3 zope . i n t e r f a c e . implements ( i n t e r f a c e s . IAddForm )4 i gno r eCon t e x t = True5 i gno r eReadon l y = True6 f i n i s h e dAdd = Fa l se78 @button . buttonAndHandler ( ( 'Add ' ) , name= ' add ' )9 def handleAdd ( s e l f , a c t i o n ) :
10 data , e r r o r s = s e l f . e x t r a c tDa ta ( )11 i f e r r o r s :12 s e l f . s t a t u s = s e l f . f o rmEr ro r sMessage13 re tu rn14 ob j = s e l f . createAndAdd ( data )15 i f ob j i s not None :16 # mark on l y as f i n i s h e d i f we17 # get the new ob j e c t18 s e l f . f i n i s h e dAdd = True
Exemplo: form.AddForm.createAndAdd
1 c l a s s AddForm(Form ) :2 ”””A f i e l d and button based add form . ”””3 zope . i n t e r f a c e . implements ( i n t e r f a c e s . IAddForm )4 i gno r eCon t e x t = True5 i gno r eReadon l y = True6 f i n i s h e dAdd = Fa l se78 ## cut ##9
10 def createAndAdd ( s e l f , data ) :11 ob j = s e l f . c r e a t e ( data )12 even t = l i f e c y c l e e v e n t . Ob j ec tCrea tedEvent ( ob j )13 zope . even t . n o t i f y ( even t )14 s e l f . add ( ob j )15 re tu rn ob j
Exemplo: renderizacao do formulario PersonAddForm
1 >>> p r i n t addForm ( ) # update ( ) e r e nd e r ( )2 <form a c t i o n=” . ”>3 <d i v c l a s s=”row”>4 < l a b e l f o r=”form−widgets−i d ”>ID</ l a b e l>5 < i n pu t type=” t e x t ” i d=”form−widgets−i d ”6 name=” form . w idge t s . i d ”7 c l a s s=” tex t−widget r e q u i r e d t e x t l i n e − f i e l d ”8 v a l u e=”” />9 </ d i v>
10 . . .11 <d i v c l a s s=” a c t i o n ”>12 < i n pu t type=” submit ”13 i d=”form−buttons−add”14 name=” form . bu t ton s . add”15 c l a s s=” submit−widget16 button− f i e l d ” v a l u e=”Add” />17 </ d i v>18 </ form>
Exemplo: form.EditForm
1 c l a s s EditForm (Form ) :2 ”””A s imp l e e d i t form with an app l y button . ”””3 zope . i n t e r f a c e . implements ( i n t e r f a c e s . IEd i tForm )45 succe s sMessage = ( 'Data s u c c e s s f u l l y updated . ' )6 noChangesMessage = ( 'No changes were a p p l i e d . ' )78 @button . buttonAndHandler ( ( ' Apply ' ) , name= ' app l y ' )9 def handleApply ( s e l f , a c t i o n ) :
10 data , e r r o r s = s e l f . e x t r a c tDa ta ( )11 i f e r r o r s :12 s e l f . s t a t u s = s e l f . f o rmEr ro r sMessage13 re tu rn14 changes = s e l f . app lyChanges ( data )15 i f changes :16 s e l f . s t a t u s = s e l f . succe s sMessage17 e l s e :18 s e l f . s t a t u s = s e l f . noChangesMessage
Exemplo: form.EditForm
1 c l a s s EditForm (Form ) :2 . .3 def applyChanges ( s e l f , data ) :4 con t en t = s e l f . ge tContent ( )5 changes = app lyChanges ( s e l f , content , data ) #**
6 # `` changes `` i s a d i c t i o n a r y ;7 # i f empty , t h e r e were no changes8 i f changes :9 # Cons t ru c t change−d e s c r i p t i o n s
10 # f o r the ob j e c t−mod i f i e d even t11 d e s c r i p t i o n s = [ ]12 f o r i n t e r f a c e , names i n changes . i t ems ( ) :13 d e s c r i p t i o n s . append (14 l i f e c y c l e e v e n t . A t t r i b u t e s ( i n t e r f a c e ,15 *names ) )16 # Send out a d e t a i l e d ob j e c t−mod i f i e d even t17 even t . n o t i f y (18 l i f e c y c l e e v e n t . Ob j e c tMod i f i edEven t (19 content ,20 * d e s c r i p t i o n s ) )21 re tu rn changes
z3c.form e a integracao com Ploe:plone.app.z3cform
Para usar o template do pacote plone.app.z3c.form, e necessarioregistrar um novo skin Layer. No profile do seu produto, ao incluirplone.app.z3c.form como dependencia, ele automaticamenteinstala esse novo Layer e dessa forma teremos a validacao in-line eoutras melhorias no template padrao:Arquivo: meuproduto/profiles/default/metadata.xml
1 <metadata>2 <v e r s i o n>1</ v e r s i o n>3 <dependencies>4 <dependency>5 p r o f i l e −p lone . app . z3cform : d e f a u l t6 </dependency>7 </dependencies>8 </metadata>
1 from p lone . z3cform . l a y o u t import wrap form2 from z3c . form import form , f i e l d34 c l a s s ApybMemberDisplayForm ( form . Form ) :5 mode = ' d i s p l a y '
6 f i e l d s = f i e l d . F i e l d s ( IApybMember ) . s e l e c t ( ' f u l l n ame ' ,7 ' o r g a n i z a t i o n ' , ' ema i l ' , ' c i t y ' , ' u f ' , ' t ype ' ,8 ' c ommun i t y r e l a t i o n ' )9 f i e l d s [ ' t ype ' ] . w i dge tFac to r y = r a d i o . Rad ioF i e l dWidge t
10 l a b e l = (u ' P e r f i l do Membro ' )11 d e s c r i p t i o n = (u ' ' ' Segue aba i xo os d e t a l h e s12 do p e r f i l do membro : ' ' ' )13 ...1415 MemberDisplayFormView = wrap form ( ApybMemberDisplayForm )
1 from p lone . z3cform . l a y o u t import wrap form2 from z3c . form import form , f i e l d34 c l a s s ApybMemberDisplayForm ( form . Form ) :5 . .6 def getContent ( s e l f ) :7 s e s s i o n = Se s s i o n ( )8 ema i l = s e l f . r e q u e s t . ge t ( ' ema i l ' , None)9 query s e s s i o n . query ( model . ApybMember )
10 member = query . f i l t e r b y ( ema i l=ema i l )11 i f not member :12 s t a t u s = IS ta tu sMes sage ( s e l f . r e q u e s t )13 message = ”Cadas t ro de membro nao encont rado ”14 s t a t u s . addStatusMessage ( message , type= ' i n f o ' )15 u r l = s e l f . c on t e x t . a b s o l u t e u r l ( )16 re tu rn s e l f . r e q u e s t . r e s pon s e . r e d i r e c t ( u r l )17 e l s e :18 re tu rn member . one ( )1920 MemberDisplayFormView = wrap form ( ApybMemberDisplayForm )
z3c.form: alterando o template de renderizacao doformulario
1 # Do not mix w i th :2 # Product s . F i v e . b rowse r V iewPageTemplateF i l e3 from zope . app . page temp la te import ViewPageTemplateFile\4 as Zope3PageTemplateF i l e56 c l a s MyForm( form . AddForm ) :7 ”””MyForm Example ”””8 temp la t e = Zope3PageTemplateF i l e ( ”my−t emp la t e . pt ” )
z3c.form: alterando o template de renderizacao doformulario
1 # Do not mix w i th :2 # Product s . F i v e . b rowse r V iewPageTemplateF i l e3 from zope . app . page temp la te import ViewPageTemplateFile\4 as Zope3PageTemplateF i l e56 c l a s MyForm( form . AddForm ) :7 ”””MyForm Example ”””8 temp la t e = Zope3PageTemplateF i l e ( ”my−t emp la t e . pt ” )