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]

Reply via email to