Wednesday, August 01, 2007

Gotcha: Turbogears Form Widget

So, I had one of those barking up the wrong tree moments this morning, where I was sure as can be there was something going on with SQLObject caching, but it turned out to be much simpler than that. I have a simple sort of application linking products to the company that makes them, but when you added a new company, then tried to add a new product for that company, the company didn't show up in the pull down box. (a SingleSelectField)

As it turns out, when you create your form widget:
editform = widgets.TableForm(
fields=EditFields(),
action="/editsave")
the field class gets created once, at the controller load, and that's it.
Therefore, if you populate your fields when you create the form, they won't be updated, possibly causing you to learn more than you wanted to about SQLObject caching. I found the solution on this page. Similar to passing values, you just pass a dictionary of the options to the appropriate widget. Since I have a generic CRUD controller, I created a function in my EditFields class that returns a dictionary of all the options fields and updated values, like so:
def updatelists(self):
"""Return a dictionary of any lists
that need to be updated due to new objects"""

companylist = Company.build_list(
'name',
orderBy=Company.q.name)

#in my form, companyID is the
#name of the SingleSelectField
return dict(companyID=companylist )

(using the build_list method here) then, in my controller:
return dict( form=self.editform,
values=objvalues,
options=self.fieldswidget.updatelists())
and finally, in my model:
<div py:content="ET(form.display(
value=values,
options=options))">
(I'm using Genshi, which is why I have the ET function there)

No comments: