On 12/16/05, Kevin Dangoor <[EMAIL PROTECTED]> wrote: > > *sigh* Things have been very disruptive for me outside of work for the > past few days. I have a feature to cleanup and two more devcasts to do > that will make some of these things clearer. I'll see what I can > clarify below and we'll see if the direction I was heading works for > you. > > On 12/16/05, Dan Jacob <[EMAIL PROTECTED]> wrote: > > > > I've been following the discussions about form handling and widgets > > lately and I think it would be fantastic if we get this aspect of > > TurboGears working right. At present it is very awkward to handle forms > > and widgets are difficult to use and extend. I also think if we get > > this aspect of TG right we will be well on the way to a Rails-and > > -Django beating framework (feature for feature). > > I agree that this is a very critical feature, and I think that the > framework that's there is a good part of the way to where it needs to > be... not 100%. (more to follow) > > > Here's my Christmas list: > > > > 1. An error_handler argument to @turbogears.expose. This would simplify > > code like this: > > > > @turbogears.expose(html="templates.form") > > def add(self): > > return dict(form=article_form()) > > > > @turbogears.expose(inputform=article_form()) > > def create(self, title, maintext, categoryID, **kw): > > if cherrypy.request.form_errors:return self.add > > # rest of function:add an article and redirect > > > > to this: > > > > @turbogears.expose(html="templates.form") > > def add(self): > > return dict(form=article_form()) > > > > @turbogears.expose(inputform=article_form(), error_handler=add) > > # go straight to adding an article and redirect, no need to check > > for errors > > I opened a ticket that does this slightly differently. We could revise > the ticket to match what you're saying here, and I think all will be > well. > > http://trac.turbogears.org/turbogears/ticket/219 > > My suggestion was this: > @turbogears.expose(validators=[...]) > def mymethod(self, **kw): > handle the good case > > def mymethod_error(self, errors, **kw): > handle the bad case > > with an optional error_handler argument: > def tackle_errors(self, errors, **kw): > handle the bad case > > @turbogears.expose(validators=[...], error_handler=self.tackle_errors) > def mymethod(self, **kw): > handle the good case > > If we get rid of the "errors" parameter, this will look much like your > suggestion. I added the errors parameter to make it more convenient to > get at the errors if you want. > > The problem that some error handling situations will have is the "edit" case: > > @expose... > def edit(self, myinstance): > ...do things... > > @expose... > def save_edits(self, myinstance, var1, var2, var3): > ...do things... > > save_edits and edit don't have the same method signature so you can't > arbitrarily call edit again as an "error_handler". > > The *nice* thing about just looking at cherrypy.request.form_errors is > that it's very simple, you've got access to all of the parameters and > you can do whatever you need to do. > > @expose... > def save_edits(self, myinstance, var1, var2, var3): > if cherrypy.request.form_errors: > return self.edit(myinstance) > > > 2. Functions to access cherrypy.request.form_errors and input_values to > > save on typing, for example: > > > > errors = turbogears.get_errors() > > turbogears.set_defaults(article.toDict()) > > I made a minor change to form handling a few days back that fixes > input_values usage. TableForm now works like other widgets: you pass > it a value at insert time. That value can be an instance or a > dictionary. So, if you're adding a new record you just pass in None > and the form's defaults take hold. If you're editing, you just pass in > an appropriate instance or dictionary. > > > 3. An "attributes" argument for widgets, for example: > > > > TextField("name", default="Ok", attrs={'size':50, 'maxlength'100'}) > > -> also for compound widgets if needed: > > > > f = TableForm(attrs={'enctype':'multipart/form-data'}, > > widget_attrs={'name', {'size':50}}) > > I'm sold on this.
You could just pass that dictionary to a py:attr, right? > > 4. A "schema" argument for Form widgets, so you can pass in a > > FormEncode schema > > Are you envisioning that you'd define a schema and then the widgets > are chosen based on that? Or are you thinking you'd hand in a schema > just for validation? What would be the advantage to using a schema for > validation rather than having a validator on each widget as it works > now? This brings up an interesting point. Should we allow for form generation based on SQLObject-like classes? > > 5. Multiple submit buttons for Forms > > This should be easy. Assuming you can set the form's "official" submit > button to None, you can hand the form as many submit button widgets as > you want. The submit button values will get passed through (which is > what you'd want if you have multiple). > > > 6. Select and radio/checkbox group widgets which select/check values > > automatically > > Yep. That's a necessity. > > > 7. Select and radio/checkbox group widgets populated automatically by > > passing in a SQLObject SelectResult > > Interesting. What would these widgets do with the selectresult? I'm assuming something like this: <option value="select_result.id">select_result.widget_parameter</option> The default text value should probably be the alternateID, if exists. > > 8. Extended SQLObject class which populates results from form request > > values. When you define a subclass you provide a __public__ list like > > so: > > > > class Article(TG_SQLObject): > > __public__=["title", "maintext", "categoryID"] > > title = StringCol(length=200) > > ....other fields > > In your controller: > > > > @turbogears.expose(..) > > def create(self, **kw): > > Article.autoCreate(author=identity.user) > > > > @turbogears.expose(..) > > def update(self, id, **kw): > > a = Article.get(id) > > a.autoUpdate(updated=datetime.now()) > > > > In both cases, the attributes "title", "maintext" and "categoryID" are > > automatically set if found in the cherrypy.request.paramMap, and > > additional fields are then passed in as arguments. This is **sort of** > > like Add/UpdateManipulators in Django. > > While working on the partially finished CRUD stuff, I found this to be > quite easy to do without adding anything to the model. I'd better try > to get that together so I can show what I mean. I can't wait to see what this is. > > 9. A PSP and world peace :-) > > World peace, sadly, isn't going to make it into TurboGears 1.0. We'll > keep trying for 2.0 :) > > You'll have to check with Santa on the PSP. > > Kevin > > -- > Kevin Dangoor > Author of the Zesty News RSS newsreader > > email: [EMAIL PROTECTED] > company: http://www.BlazingThings.com > blog: http://www.BlueSkyOnMars.com > -- [EMAIL PROTECTED]

