My objective is to be able to hand-code my own view containing a form that I can layout exactly as I want but retain the benefits of accepts() re validation and db updating.
I found 2 obstacles with web2py out-of-the box: 1) In my view (I have less than 1 week of python), I did not have easy access to the latest version of a field: defaults could be in form.record.my_field (but not for a new record) but if the user has input data then it is in form.vars.my_field. I wanted a consistent source and the only place is form.components but extracting the values in the view seems difficult due to the nested nature of components. 2) For dropdown lists, the value is not enough. I want the whole <select><options> etc including which option is selected. If I can achieve the above there are a couple of other requirements: 3) For completeness, support for the session/formkey mechanism and any other hidden fields that may be specified. 4) If I display the whole control (as in 2) above), I don't want any pre-formatted errors. I can get the necessary info from form.errors. With my solution, the usage is as follows: - in a controller, after the SQLFORM(db.recipe) or FORM(whatever) is created add form.customview=True - in a view, after the <form> tag for your custom form add {{=form}} - this will create a Storage called 'latest' in FORM with a 'value' and a 'component' for each fieldname and return the following: <!-- custom view --> <input value="130911852535" type="hidden" name="_formkey" /> <input value="recipe" type="hidden" name="_formname" /> ... plus any other hidden INPUTS specified in the form - if you just want the latest value for a fieldname 'name' then code something like <input type="text" name="name" value="{{=form.latest.name['value']}}"/ > - if you just want the whole control then code something like {{=form.latest.name['component']}} to get <input type="text" class="string" name="name" value="Cornish Pasty" id="recipe_name" />" - or, where the field has IS_IN_SET, code {{=form.latest.type['component']}} to get <select class="string" name="type" id="recipe_type"><option value="A">accompaniment</option><option value="C">component</ option><option value="R" selected="selected">recipe</option></select> So, assuming anyone's still interested, what changes did I make to the web2py code? Well, it's all in html.py and makes use of a new Storage attribute called 'latest' added to FORM if customview is present and True: a) replace the existing FORM.xml() method with the following: def xml(self): if self.customview and self.customview==True: self._latestdata() # return hidden INPUTs in response to {{=form}} hidden='' field=self.latest['hidden'] for component in field['component']: hidden+=component.xml()+'\n' return '<!-- custom view -->\n'+hidden else: # exactly the same as old xml() except hidden logic in common method _hiddendata([]) newform=FORM(*self.components,**self.attributes) self._hiddendata(newform.components) return DIV.xml(newform) # common method for creating/storing formkey and creating hidden INPUTs - taken from original xml() def _hiddendata(self, components): if self.session!=None: _formkey='_formkey[%s]' % self.formname key=self.session[_formkey]=str(random.random())[2:] components.append(INPUT(_type='hidden',_name='_formkey',_value=key)) if self.formname!=None: components.append(INPUT(_type='hidden',_name='_formname',\ _value=self.formname)) if self.attributes.has_key('hidden'): hidden=self['hidden'] for key,value in hidden.items(): components.append(INPUT(_type='hidden',_name=key,_value=value)) # create the Storage to hold value and component for each fieldname + one for 'hidden' INPUTs def _latestdata(self): self.latest=Storage() components=[] self._hiddendata(components) self.latest['hidden']={'value':'hidden','component':components} for component in self.components: component._latestdata(self.latest) a) add the following to DIV to find the required component and store in latest Storage def _latestdata(self, latest): # the following code checks whether the component can have user input and # if true stores the value and component using the latestitem helper # if false iterates through child components if self.attributes.has_key('_value') and\ self.attributes.has_key('_name'): latest[self.attributes['_name']]=self.latestitem(self.attributes['_value'],self) elif isinstance(self,SELECT) and\ self.attributes.has_key('_name'): latest[self.attributes['_name']]=self.latestitem(None,self) elif isinstance(self,TEXTAREA) and\ self.attributes.has_key('value') and\ self.attributes.has_key('_name'): value=self.attributes['value'] if value==None: value='' latest[self.attributes['_name']]=self.latestitem(value,self) elif self.components: for c in self.components: if hasattr(c,'_latestdata'): c._latestdata(latest) # store value and component ensuring any errors are ignored def latestitem(self, value, component): component.errors=None return {'value':value,'component':component} That's it - it all seems to work a treat. All feedback gratefully received (this is where Massimo tells me it could all have been done with 2 lines of python and a regex) :-) Bill --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "web2py Web Framework" group. To post to this group, send email to web2py@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/web2py?hl=en -~----------~----~----~----~------~----~------~--~---