TurboGears forms first look

2 views
Skip to first unread message

Kevin Dangoor

unread,
Nov 1, 2005, 11:05:24 PM11/1/05
to turbo...@googlegroups.com
For anyone wondering why I've been somewhat quieter than normal... we
had guests over the weekend, and...

There has been a lot of activity around form generation lately, which
has been very helpful. There are many different ideas floating around
out there, and those have given me lots of food for thought for how to
handle form generation and, ultimately, CRUD in TurboGears.

Today, I checked in the first bit of code for TurboGears' form
generator. (Aside: if you have any thoughts on naming for the forms
package, that'd be good. turbogears.forms seems lame.)

There's a fair bit more to my thoughts on this subject than what
currently appears in the code, but there's enough there that I wanted
to talk about it, start getting some more opinions, and see where
people might want to help out.

Rolling Our Own?
----------------

TurboGears has become famous as a "megaframework", integrating other
tools to do the bulk of its work. With so much going on in form
generation, why create a new package?

Before I start hearing calls of "Not Invented Here" syndrome, I'll
point out that I've already started working on deprecating TestGears
in favor of Nose. Believe me, I want to work on apps and I'm happy to
get all of the assistance I can in building out the framework to
create useful apps.

Creating and dealing with forms is an crucial part of making a web
application. Moving data to and from forms is a big part of a web app,
and making that easy is important. CherryPy's method of taking
incoming parameters and mapping them to method parameters is really
nice, but it's only a piece of dealing with forms.

Because dealing with forms is so central to a web app, assistance with
those forms will be an integral part of TurboGears. This is why we're
rolling our own forms system... where else will we find a forms
package that tightly integrates with turbogears.expose, uses Kid for
templating and helps out with SQLObject? MochiKit will likely get into
the act in short order as well.

Rolling our own forms package doesn't mean ignore what's out there.
The FormEncode validators play an important part. But, beyond that,
design ideas are coming from all over the place. We might not be using
all of the code that exists out there, but I do hope we're learning
from the choices people have previously made.

Code Generation vs. API
-----------------------

Rails takes a very simple, yet still effective approach to
customization of automatically created forms: you generate the code
and the modify the files. This is effective, because some kind of
customization is nearly always required. Of course, it also has the
drawbacks of any code generation system: what happens when you would
need to regenerate the code because of other changes in the system?

Rails does go a bit beyond code generation, though. It provides
functions that you call for generating text fields, etc.

What I'm shooting for is a system that provides easy and flexible
customization in such a way that you can realistically use the
automatic API with minimal tweaks. This will help keep your UI in sync
with your code.

At the same time, I'm looking to offer code generation as well, for
people who need absolute and total customization.

Widgets
-------

The key to this is the widgets. Widgets live in Python code but are
rendered by Kid templates. Right now, there's only a couple of them
and I'm not going to write much about them, because there are some
parts of the API that are not fully hashed out yet. You could start
writing widgets right now, if you wish, but you'd likely have to
rewrite bits as the API fills in.

So, with the teaser that widgets are the key, I'm going to stop
talking about widgets for now.

Forms
-----

Instead, I'll talk a bit about forms. A form is actually a widget, but
it has special logic for dealing with a collection of widgets that it
holds on to.

You can instantiate a form like this:
myform = TableForm(widgets=[
widgets.TextField("name"),
widgets.TextField("address"),
widgets.TextField("age", default=0,
validator=validators.Int())])

A TableForm displays a label for each field in one column of a table,
with the field controls in another column of the table. A TableForm
gives you a submit button for free. As you can see from this example,
a widget can have a default value and widgets can have validators.
Validators are important because they can handle complex
back-and-forth between Python and the web.

When you want to display the form, you can do something like this:

@turbogears.expose(html="fancy.template")
def index(self):
return dict(form=myform)

Then, in the template, you would do something like this:
<div py:replace="form.insert(action='save')"/>

Voila! You have a form.

Actually, this API is going to change subtly. There will be an expose
parameter to specify forms that are present in the template. Since we
gave the form an action of "save", we should define a save method:

@turbogears.expose()
def save(self, name, address, age):

There are two problems with this definition, though:
1) what happens to the incoming submit button?
2) shouldn't age be validated?

expose now has a new input_form parameter.

@turbogears.expose(input_form=myform)
def save(self, name, address, age):

By specifying that data is coming from that form, the widgets will
each get a chance to validate the incoming data and convert it from
whatever web format it was in to a convenient Python parameter. "age",
when it arrives, will be an int. Also, since the form knows what the
submit button was called, it is automatically thrown out. (Someone's
probably going to say "hey! I need that submit button value!"...
widgets are customizable through standard Python means. Subclass and
override. Piece of cake.)

What if the user entered "forty-two" for their age? Well, the
validation will fail. As declared above, an attempt would be made to
call validation_error, otherwise an exception is raised. Since the use
of the validation_error method has been painful, I've added another
approach to error handling.

@turbogears.expose(input_form=myform)
def save(self, name, address, age, has_errors):

By adding a has_errors parameter, you're signaling to TurboGears that
this method is prepared to deal with validation issues that come up.
TurboGears automatically throws out the invalid values and will pass
in None in their place. In this example, age would be None.

The validation errors that came up can be found in
cherrypy.request.form_errors. The valid values from the input form are
stored in cherrypy.request.input_values. You could probably do
productive things with those two values but, luckily, you don't have
to. To handle that problem with the "age" input:

@turbogears.expose(input_form=myform)
def save(self, name, address, age, has_errors):
if has_errors:
return self.index()

The form will be redisplayed with good values prepopulated and the
invalid ones thrown out. An error message would be displayed next to
the "age" field on the form. And we all heave a sigh of relief that we
didn't have to do that in validation_error :)

That's It For Today
-------------------

I'd welcome comments on any of this. This part of things is fairly
well baked, so we can reasonably discuss this in a mediumly-trafficked
google group of 550+ people.

If you find that you have some time on your hands over the next couple
of days and want to work on this a bit, send me a private email. I
think there are some areas where the work can be split off without
stepping all over each others' toes.

Once the widgets are more fully baked (tomorrow, hopefully), there
will be lots of room for people to contribute work on widgets!

--
Kevin Dangoor
Author of the Zesty News RSS newsreader

email: k...@blazingthings.com
company: http://www.BlazingThings.com
blog: http://www.BlueSkyOnMars.com

Jeff Grimmett

unread,
Nov 1, 2005, 11:28:38 PM11/1/05
to turbo...@googlegroups.com
On 11/1/05, Kevin Dangoor <dan...@gmail.com> wrote:

For anyone wondering why I've been somewhat quieter than normal... we had guests over the weekend, and...

You have a life outside of Python code? Where'd you download THAT?  ;-)

Today, I checked in the first bit of code for TurboGears' form
generator. (Aside: if you have any thoughts on naming for the forms
package, that'd be good. turbogears.forms seems lame.)

Everything below this is well above my head - I'm really new to web apps - but I will comment on this.

Keep it simple. turbogears.forms is concise, to the point. It tells me everything I need to know about what the module will do.

Not to put too fine a point on it, but consider another fairly popular framework that I'll call, uh, "knotted" for illustrative purposes. Does the name " knotted.sandwich.pastrami" really tell you a lot about what the module does? It may be the heart and soul of tw -- er, "knotted"'s authentication system, but it's not too obvious from the name of the module.

I'm a nuts and bolts guy. Direct, unambiguous naming conventions rock my world, pythonically speaking.

Of course, that may be an unpopular opinion. Maybe a poll? :-)

At any rate, I'm very interested in your thoughts on the forms module, where it's going, etc. It almost looks like you're using a wxWidgets model, based in HTML instead of a windowing shell - which seems logical to me. wxWidgets builds almost every 'widget' off of a few basic core widgets, in various combinations, and it works quite well for making Python GUI apps [1]. I can't see any harm at all in emulating (whether it's deliberate or not) a model that works.

[1] I'm sure other GUI libraries use a similar model, but wx is what I am most familiar with, so that's where I'm going to restrict my comments

--
"Things fall apart. The Center cannot hold."
                  - Life as a QA geek, in a nutshell.

Best,

    Jeff

Ian Bicking

unread,
Nov 1, 2005, 11:29:04 PM11/1/05
to turbo...@googlegroups.com
Kevin Dangoor wrote:
> You can instantiate a form like this:
> myform = TableForm(widgets=[
> widgets.TextField("name"),
> widgets.TextField("address"),
> widgets.TextField("age", default=0,
> validator=validators.Int())])

Isn't that just begging to be...

class myform(TableForm):
name = widgets.TextField()
address = widgets.TextField()
age = widgets.TextField(default=0, validator=validators.Int())

?

--
Ian Bicking | ia...@colorstudy.com | http://blog.ianbicking.org

Jeff Grimmett

unread,
Nov 1, 2005, 11:31:07 PM11/1/05
to turbo...@googlegroups.com
On 11/1/05, Ian Bicking <ia...@colorstudy.com> wrote:

Kevin Dangoor wrote:
> You can instantiate a form like this:
> myform = TableForm(widgets=[
>                 widgets.TextField("name"),
>                 widgets.TextField("address"),
>                 widgets.TextField("age", default=0,
>                                 validator=validators.Int())])

Isn't that just begging to be...

class myform(TableForm):
    name = widgets.TextField()
    address = widgets.TextField()
    age = widgets.TextField(default=0, validator=validators.Int())


+1 insightful

bon...@gmail.com

unread,
Nov 1, 2005, 11:37:00 PM11/1/05
to TurboGears
Basically, something like the FormEncode Schema, with
appearance/behaviour attributes. I would also like to see it been able
to init/define from a dictionary, again like Schema.

Yesh

unread,
Nov 2, 2005, 12:00:53 AM11/2/05
to TurboGears
Perhaps it'll help if we could itemize/model a few business application
forms. Specifically the patterns (UI structure, data-model, and the
interaction.)

What I've experienced is that it (forms generators) quickly degenerate
into a closed loop motor that's sort of hard to customize/change for
unexpected usage scenerios.

I agree with a users comment to keep it simple. Allow a few
applications to be built which will also lead to better case-studies
and docs.

Tim Lesher

unread,
Nov 2, 2005, 12:01:23 AM11/2/05
to turbo...@googlegroups.com
On 11/1/05, Jeff Grimmett <grimm...@gmail.com> wrote:
> On 11/1/05, Kevin Dangoor <dan...@gmail.com> wrote:
>
> > Today, I checked in the first bit of code for TurboGears' form
> > generator. (Aside: if you have any thoughts on naming for the forms
> > package, that'd be good. turbogears.forms seems lame.)
>
> Keep it simple. turbogears.forms is concise, to the point. It tells me
> everything I need to know about what the module will do.
>
> Not to put too fine a point on it, but consider another fairly popular
> framework that I'll call, uh, "knotted" for illustrative purposes. Does the
> name " knotted.sandwich.pastrami" really tell you a lot about what the
> module does? It may be the heart and soul of tw -- er, "knotted"'s
> authentication system, but it's not too obvious from the name of the module.

I'll second that. Actually, twisted's names I don't mind. I find py's
much worse--"wait... which is shell and which is crust? Filling?
Argh..."

turbogears.forms is just fine.
--
Tim Lesher <tle...@gmail.com>

Tim Lesher

unread,
Nov 2, 2005, 12:20:40 AM11/2/05
to turbo...@googlegroups.com
Now that I've read this a few times, I think I see where you're going with this.

On 11/1/05, Kevin Dangoor <dan...@gmail.com> wrote:
> Code Generation vs. API

Good so far. Write-once code generation is a symptom, not a solution--
see http://c2.com/cgi/wiki?CodeGenerationIsaDesignSmell


> Widgets

From what I can tell, TG's widgets sound like more ubiquitous versions
of Spyce's Active Tags. Is that the case? What are some of the
differences?

Active Tags are the only thing I really miss from Spyce (other than
errors in .py files not bringing down the server... but more on that
another time).


> A TableForm displays a label for each field in one column of a table,
> with the field controls in another column of the table. A TableForm
> gives you a submit button for free.

...but it doesn't force you to use its submit button, right? Right?

> Also, since the form knows what the
> submit button was called, it is automatically thrown out. (Someone's
> probably going to say "hey! I need that submit button value!"...
> widgets are customizable through standard Python means. Subclass and
> override. Piece of cake.)

Thanks. :-)


> The form will be redisplayed with good values prepopulated and the
> invalid ones thrown out. An error message would be displayed next to
> the "age" field on the form. And we all heave a sigh of relief that we
> didn't have to do that in validation_error :)

Not bad so far... what is has_errors (other than something that
doesn't evaluate to boolean false)? It would be convenient to have it
be a dict of keys_with_errors:bad_value, and then your 'if' would
still work.
--
Tim Lesher <tle...@gmail.com>

Yesh

unread,
Nov 2, 2005, 12:24:20 AM11/2/05
to TurboGears
Example business forms could be.
RFQ, Quotation, Customer order form, Invoice, Shipping doc, Sales
return processing form, Purchase order (supplier), Goods recieved
document (inventory), Supplier invoice (bill), Stock transfer (from to
inventory locations), AMC (service contract), Service request form,
Material request form (purchase indent), Expense statement, Credit
note, Debit note, Journal voucher, Payment voucher, Receipt voucher.

PS: If this is not the sort of inputs that this topic requires please
mention.

Yesh

unread,
Nov 2, 2005, 12:48:53 AM11/2/05
to TurboGears
Form security/privelege must be built-in. If there's a way to markup
(with titles and description)
different zones in a form and have a seperate resource file that can
be edited to controll access to zones in a form than customer rollout
will be that
much easier.

gsteff

unread,
Nov 2, 2005, 3:03:51 AM11/2/05
to TurboGears
> Isn't that just begging to be...

> class myform(TableForm):
> name = widgets.TextField()
> address = widgets.TextField()
> age = widgets.TextField(default=0, validator=validators.Int())

Well, it depends on whether you think the name of the field in the form
belongs to the field or the form. I've implemented basic form
generation toolkits both ways, and generally think its cleaner to make
it belong to the form as above (since that reinforces the idea that no
two fields can have the same name), but there are reasons to make it
belong to the field too... for example, turbogears.forms currently uses
the name to create a default label if no other label is provided.
Obviously, you can accomplish whatever you want either way, its just a
question of which is more natural.

I actually like the idea of making the name belong to the form, but
using the dict style interface ( form['name'] = widgets.TextField() ).
Unfortunately, this makes it more awkward to make widgets themselves
part of the form definition, since elements, unlike attributes, aren't
part of class definitions (am I using the right terminology here?).

But I agree that the "widgets=[...]" syntax isn't the most natural,
though I don't know what other tradeoffs might have been involved in
choosing it.

Greg

william

unread,
Nov 2, 2005, 4:09:13 AM11/2/05
to TurboGears
This sounds similar to Quixote Form and widgets.

Have you look at that ?

William

Kevin Dangoor

unread,
Nov 2, 2005, 9:29:15 AM11/2/05
to turbo...@googlegroups.com
On 11/1/05, Ian Bicking <ia...@colorstudy.com> wrote:
>
> Kevin Dangoor wrote:
> > You can instantiate a form like this:
> > myform = TableForm(widgets=[
> > widgets.TextField("name"),
> > widgets.TextField("address"),
> > widgets.TextField("age", default=0,
> > validator=validators.Int())])
>
> Isn't that just begging to be...
>
> class myform(TableForm):
> name = widgets.TextField()
> address = widgets.TextField()
> age = widgets.TextField(default=0, validator=validators.Int())
>
> ?

I don't think so. In this example, I'm not looking to create something
that creates forms (a class), I'm looking for a form itself (an
instance).

Kevin

Kevin Dangoor

unread,
Nov 2, 2005, 9:32:18 AM11/2/05
to turbo...@googlegroups.com
On 11/1/05, Jeff Grimmett <grimm...@gmail.com> wrote:
> On 11/1/05, Kevin Dangoor <dan...@gmail.com> wrote:
>
> > For anyone wondering why I've been somewhat quieter than normal... we had
> guests over the weekend, and...
>
> You have a life outside of Python code? Where'd you download THAT? ;-)

I googled for "life" and ended up buying one on eBay :)

>
> > Today, I checked in the first bit of code for TurboGears' form
> > generator. (Aside: if you have any thoughts on naming for the forms
> > package, that'd be good. turbogears.forms seems lame.)
>
> Everything below this is well above my head - I'm really new to web apps -
> but I will comment on this.
>
> Keep it simple. turbogears.forms is concise, to the point. It tells me
> everything I need to know about what the module will do.
>
> Not to put too fine a point on it, but consider another fairly popular
> framework that I'll call, uh, "knotted" for illustrative purposes. Does the
> name " knotted.sandwich.pastrami" really tell you a lot about what the
> module does? It may be the heart and soul of tw -- er, "knotted"'s
> authentication system, but it's not too obvious from the name of the module.

OK, that's a fine argument. turbogears.forms it is. I guess I don't
want to get ri.diculo.us with the names anyhow.

I like your example. I think I remember this line in the source for
knotted.sandwich.pastrami:

import pickle

and I just couldn't convince the devs to hold the pickle.

Kevin

Kevin Dangoor

unread,
Nov 2, 2005, 9:34:28 AM11/2/05
to turbo...@googlegroups.com
On 11/1/05, bon...@gmail.com <bon...@gmail.com> wrote:
>
> Basically, something like the FormEncode Schema, with
> appearance/behaviour attributes. I would also like to see it been able
> to init/define from a dictionary, again like Schema.

Can you be more specific about defining from a dictionary? You really
want something ordered for a form to be sure that everything winds up
correctly on the form. (And yes, there are ordered dictionaries, but
i'm trying to figure out what use case is being solved here...)

Kevin

Kevin Dangoor

unread,
Nov 2, 2005, 9:39:00 AM11/2/05
to turbo...@googlegroups.com
Since we've all developed forms-based apps in the past, I've been
going more granular than this at this stage. There are things we
*know* we need (this is just a sampling)

* completely customizable appearance (with JavaScript and CSS as needed)
* repeating fields
* validation/repopulation and errors on invalid input
* wizards/multi-page forms

I am certainly working with realistic examples as I'm writing this
code, but I'm not really treading new ground... it's just a different
path in the same area as those who have come before.

And, we're a large enough group now that I'm sure people will speak up
in the places where it falls short. (That's part of the goal of
0.9...)

Kevin

Kevin Dangoor

unread,
Nov 2, 2005, 9:43:57 AM11/2/05
to turbo...@googlegroups.com
On 11/2/05, Tim Lesher <tle...@gmail.com> wrote:
> > Widgets
>
> From what I can tell, TG's widgets sound like more ubiquitous versions
> of Spyce's Active Tags. Is that the case? What are some of the
> differences?
>
> Active Tags are the only thing I really miss from Spyce (other than
> errors in .py files not bringing down the server... but more on that
> another time).

Ahh, more prior art to check out. It's been a while since I looked at
Spyce. If memory serves, active tags are kind of like JSP tags. I
should take a closer look though to make sure I'm not missing
something interesting.

> > A TableForm displays a label for each field in one column of a table,
> > with the field controls in another column of the table. A TableForm
> > gives you a submit button for free.
>
> ...but it doesn't force you to use its submit button, right? Right?

What? You want a different kind of submit button? That's asking a bit
much, isn't it? :)

You can customize the submit button text with a parameter to the form,
and you can also give it a different widget to use for the submit
button.

> > Also, since the form knows what the
> > submit button was called, it is automatically thrown out. (Someone's
> > probably going to say "hey! I need that submit button value!"...
> > widgets are customizable through standard Python means. Subclass and
> > override. Piece of cake.)
>
> Thanks. :-)
>
>
> > The form will be redisplayed with good values prepopulated and the
> > invalid ones thrown out. An error message would be displayed next to
> > the "age" field on the form. And we all heave a sigh of relief that we
> > didn't have to do that in validation_error :)
>
> Not bad so far... what is has_errors (other than something that
> doesn't evaluate to boolean false)? It would be convenient to have it
> be a dict of keys_with_errors:bad_value, and then your 'if' would
> still work.

Right now, it's just a boolean. You can get the keys with errors by
grabbing cherrypy.request.form_errors.keys()

I'm going to guess that most uses of has_errors will just be to punt
to another method.

Kevin

Kevin Dangoor

unread,
Nov 2, 2005, 9:46:46 AM11/2/05
to turbo...@googlegroups.com
While I do agree that avoiding two widgets with the same name is
handy, I personally find it more natural to make an instance of a
class when I want to actively use something than to define a new
class.

The advantage to using a list is that it's strictly ordered and Python
provides built in mechanisms to work with it while preserving the
order.

Kevin

Tim Lesher

unread,
Nov 2, 2005, 9:53:53 AM11/2/05
to turbo...@googlegroups.com
On 11/2/05, Kevin Dangoor <dan...@gmail.com> wrote:
> > ...but it doesn't force you to use its submit button, right? Right?
>
> What? You want a different kind of submit button? That's asking a bit
> much, isn't it? :)
>
> You can customize the submit button text with a parameter to the form,
> and you can also give it a different widget to use for the submit
> button.

Right... I meant to type "submit button text".

> Right now, it's just a boolean. You can get the keys with errors by
> grabbing cherrypy.request.form_errors.keys()

Hmm... if you can always get the form errors from this attribute,
isn't has_errors redundant? DRY, and all...

--
Tim Lesher <tle...@gmail.com>

Kevin Dangoor

unread,
Nov 2, 2005, 9:54:15 AM11/2/05
to turbo...@googlegroups.com
On 11/2/05, william <wil...@opensource4you.com> wrote:
>
> This sounds similar to Quixote Form and widgets.
>
> Have you look at that ?

Months ago. I just took another look, and you're right there are quite
a few similarities. I think you'll find similarities all over. These
packages are all trying to solve the same problems.

Kevin

Kevin Dangoor

unread,
Nov 2, 2005, 9:58:49 AM11/2/05
to turbo...@googlegroups.com
On 11/2/05, Tim Lesher <tle...@gmail.com> wrote:
> > Right now, it's just a boolean. You can get the keys with errors by
> > grabbing cherrypy.request.form_errors.keys()
>
> Hmm... if you can always get the form errors from this attribute,
> isn't has_errors redundant? DRY, and all...

That's a good point. If we deprecate validation_error, then the method
can just be called directly and you can check form_errors to see if
there's a problem. I think this also means that an invalid exception
would never be raised.

It simplifies the code, but it does also eliminate a visual reminder
to check for errors. Maybe that's not so bad, though.

Kevin

Ian Bicking

unread,
Nov 2, 2005, 11:27:24 AM11/2/05
to turbo...@googlegroups.com
I'm thinking from a syntactic point of view, not necessarily the
classness. This is similar to FormEncode schemas.

They can remain ordered, if TextField uses a counter to track when they
were created relative to each other.

OTOH, this is something that creates forms! You can't send this Python
code to the client, you send what this code renders, in the context of a
specific request. That is a reasonable way to distinguish classes and
instances.

--
Ian Bicking / ia...@colorstudy.com / http://blog.ianbicking.org

Gunfighter

unread,
Nov 2, 2005, 1:06:44 PM11/2/05
to TurboGears
Name suggestion: TurboForms

lbolo...@gmail.com

unread,
Nov 2, 2005, 1:37:40 PM11/2/05
to TurboGears

Kevin Dangoor wrote:
> For anyone wondering why I've been somewhat quieter than normal... we
> had guests over the weekend, and...
>
> There has been a lot of activity around form generation lately, which
> has been very helpful. There are many different ideas floating around

Hi Kevin I posted a demo of how I personally deal with form validation
and stuff on the CherryPy users list:

http://groups.google.com/group/cherrypy-users/browse_thread/thread/6fcd3ac9786bac6a/

It's a very primitive way of dealing with it but it could be somewhat
automated... I'm just waiting a bit more to analyze my usage patterns
of it. As of now I like it because it doesn't get at all in your way
and resembles ASP.NET validation handling even if it currently plays at
a much lower level than their system does. Also it doesn't pretend to
compete with Bicking's FormEncode... I would never dare, it's just the
way I like ;-)

Lorenzo

Kevin Dangoor

unread,
Nov 2, 2005, 1:56:26 PM11/2/05
to turbo...@googlegroups.com
Hi Lorenzo,

On 11/2/05, lbolo...@gmail.com <lbolo...@gmail.com> wrote:
> Hi Kevin I posted a demo of how I personally deal with form validation
> and stuff on the CherryPy users list:

I saw your message, but I only looked at the code just now...

The ideas there are fairly similar. Your code looks a bit like
FormEncode, but does not do the two-way conversion (to_python,
from_python). Why did you choose to not use FormEncode?

Thanks for the link to your example!

Kevin

David Bernard

unread,
Nov 2, 2005, 4:45:34 PM11/2/05
to TurboGears
Hi,

For my own crud application, I choose to generate kid template (and
checksum) at startup time. Previous templates was erased if the
chechsum of the existing templates (or if no template exists) check the
templates.
Advantages :
* generate templates that could be compiled by Kid
* user could choose to modify the templates, without need to know the
"form/widget" framework, and avoid the blank page syndrome
* user could customize widget for a more global impact and don't need
to edit templates
* user could mixed both customization facilities

About Widget, I use the same approach as Kevin except I use the
argument order instead of declare an explicite array =>
myform = TableForm(widgets.TextField("name"),


widgets.TextField("address"),
widgets.TextField("age", default=0,

validator=validators.Int()))

I also use the 3 parameter "key/fieldname", "validator" only for
widgets used for editing, and "default". I define 2 bases types for
widgets :
* Widget : use to display or edit one field
* WidgetsList : use as composite of Widget or WidgetsList
And for the crud, I define 3 families : edit, view, list

About error handling, I choose the had for every field entry in the
dict, a field names 'field_error_' set by editing widget (default is
None), like this the kid template is simple (%(key)s is replaced by the
key/fieldname):
<tr py:if="%(key)s_error_" colspan="2">
<td class="error" py:content="str(%(key)s_error_)"/>
</tr>

I also define based on the TurboEngine code a controller, and the (3)
automatics WidgetsList generators from SQLObject.

Kevin, If your interested I could send you the "crudgear" draft, and
I'll be happy to help you, like this I could work on my TG application
(night only and often offline) andbe sync with last dev.

lbolo...@gmail.com

unread,
Nov 3, 2005, 10:34:36 PM11/3/05
to TurboGears
Kevin Dangoor wrote:

> The ideas there are fairly similar. Your code looks a bit like
> FormEncode, but does not do the two-way conversion (to_python,
> from_python). Why did you choose to not use FormEncode?

Actually my validators didn't pretend to be comprehensive... I think
that if I was to validate something like an int I would come up with
something like Ian did. C# being statically typed AFAIK they validate
numeric values with regexes but then, of course the value in the
underlying "business logic" is treated like an int or whatever. ASP.NET
validators are really a no-brainer.

I just rolled my own because even with Groovie's tutorial I couldn't
really figure out how to make stuff work my way.

> Thanks for the link to your example!

You're welcome!

Lorenzo

gsteff

unread,
Nov 4, 2005, 2:08:27 AM11/4/05
to TurboGears
I like the idea of providing the sequence of widgets via *args instead
of an explicit list.

Greg

Kevin Dangoor

unread,
Nov 4, 2005, 8:16:24 AM11/4/05
to turbo...@googlegroups.com
On 11/4/05, gsteff <greg.st...@gmail.com> wrote:
>
> I like the idea of providing the sequence of widgets via *args instead
> of an explicit list.

I do, too. I think I'll change that...

Kevin

Krys Wilken

unread,
Nov 13, 2005, 2:13:55 PM11/13/05
to turbo...@googlegroups.com
Hi guys,

For my $0.02, I'd just like to say that I prefer the class definition
idea. It is visually cleaner to me and we all know that code is read
more than it is written. :-)

I also agree with Ian's interpretation of "what it means" to create a
form instance. The instance in this case is just a string with (x)html
tags in it. The class is what creates that string.

This is all probably more a matter of taste, but everything else in TG,
SO and CPy is class-based, and it seems a bit inconsistent to me to have
forms work as a list-based system.

Anyway, like I said, this is my $0.02.

Other than that syntactic issue, I really like the way you are going
with this, Kevin. TG is a beautiful piece of code and just keeps
getting better! :-) Thanks for making my life easier! :-)

Krys
Reply all
Reply to author
Forward
0 new messages