django.forms-style value cleaning, validation and error collecting

639 views
Skip to first unread message

Michael Nelson

unread,
May 15, 2011, 11:13:30 AM5/15/11
to golan...@googlegroups.com
I was just wondering if there are plans, or anyone is working on
something similar to Django forms in go (input cleaning, validation
and error collection)[1]? I've checked both the packages dashboard and
the archives for this group, and couldn't see anything, but it seems
to be something that would make handling web requests much cleaner.

I thought it'd make a nice learning project (as it'd be learning to
think of the go-way for problems that have already had a lot of
thought in other languages) and will probably start, but would prefer
to contribute to something that's already started if it exists.

Thanks!

[1] http://docs.djangoproject.com/en/1.3/topics/forms/

--
-
Michael Nelson
http://liveandletlearn.net
http://micknelson.wordpress.com

Kyle Lemons

unread,
May 15, 2011, 4:43:46 PM5/15/11
to Michael Nelson, golang-nuts
Depending on how advanced you want it to be, this could be a very interesting project, but it might not be the first thing you want to tackle (my idea relies heavily upon reflection) if you are new to Go.  I've idly thought about how I would do this (I also have not seen anything so far), and my idea basically comes down to:

1. Use reflection and struct tags to convert a structure into a web form and process the results back into the structure
2. Integrate with the template library to insert the form into a webpage nicely, possibly customize it, etc

This is not to say that there aren't other, perfectly legitimate ways to handle this in Go, this is just one potentially Go-like idea that I've come up with.

Since a package that handles forms would tend to be very high level, it may or may not be a candidate for inclusion into the standard library, but if it made it very easy to do web forms and was sufficiently hardened against injection attacks, it might be a good candidate for going into the standard appengine libraries.  If you built accessibility into it (using labels, tabindex, titles, etc), it could also increase the quality of go webapps in general.
--
~Kyle

"Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?" 
— Brian Kernighan

Michael Nelson

unread,
May 16, 2011, 1:45:55 AM5/16/11
to Kyle Lemons, golang-nuts
On Sun, May 15, 2011 at 10:43 PM, Kyle Lemons <kev...@google.com> wrote:
> Depending on how advanced you want it to be, this could be a very
> interesting project, but it might not be the first thing you want to tackle
> (my idea relies heavily upon reflection) if you are new to Go.

Yes, I wasn't planning on tackling model-form type functionality
(auto-generation of forms based on data definitions). I'm just
starting by putting together a small library of fields (CharField,
RegexField) etc., that support cleaning and errors etc., and was
planning on a BaseForm that can be composed together with the relevant
fields to provide a form.Clean() (which may require a little
reflection), IsValid and CleanedData.

> I've idly
> thought about how I would do this (I also have not seen anything so far),
> and my idea basically comes down to:
> 1. Use reflection and struct tags to convert a structure into a web form and
> process the results back into the structure
> 2. Integrate with the template library to insert the form into a webpage
> nicely, possibly customize it, etc

Great, but I'm hoping both those points will be orthogonal to form
field cleaning and error collection... what do you think? I'm keen to
work on the basics first :)

Thanks!

> This is not to say that there aren't other, perfectly legitimate ways to
> handle this in Go, this is just one potentially Go-like idea that I've come
> up with.
> Since a package that handles forms would tend to be very high level, it may
> or may not be a candidate for inclusion into the standard library, but if it
> made it very easy to do web forms and was sufficiently hardened against
> injection attacks, it might be a good candidate for going into the standard
> appengine libraries.  If you built accessibility into it (using labels,
> tabindex, titles, etc), it could also increase the quality of go webapps in
> general.
> --
> ~Kyle
> "Everyone knows that debugging is twice as hard as writing a program in the
> first place. So if you're as clever as you can be when you write it, how
> will you ever debug it?"
> — Brian Kernighan
>

--

http://micknelson.wordpress.com/

André Moraes

unread,
May 16, 2011, 10:38:20 AM5/16/11
to golang-nuts
Great idea,

Something like that will be very handy.

--
André Moraes
http://andredevchannel.blogspot.com/

Islan Dberry

unread,
May 16, 2011, 12:29:44 PM5/16/11
to golan...@googlegroups.com
The web.go code for reading a form into a struct might be of interest to you:

Michael Nelson

unread,
May 17, 2011, 5:28:55 PM5/17/11
to golan...@googlegroups.com
On Sun, May 15, 2011 at 5:13 PM, Michael Nelson <absol...@gmail.com> wrote:
> I was just wondering if there are plans, or anyone is working on
> something similar to Django forms in go (input cleaning, validation
> and error collection)[1]? I've checked both the packages dashboard and
> the archives for this group, and couldn't see anything, but it seems
> to be something that would make handling web requests much cleaner.
>
> I thought it'd make a nice learning project (as it'd be learning to
> think of the go-way for problems that have already had a lot of
> thought in other languages) and will probably start, but would prefer
> to contribute to something that's already started if it exists.

I've done an initial trial supporting forms with CharField,
IntegerField and RegexField, to do things like:

{{{
egForm := forms.NewForm(
forms.NewCharField("description"),
forms.NewIntegerField("purchase_count"))
}}}

You can then set the form input data (from http.Request.Form), call
egForm.IsValid(), and access either the egForm.CleanedData() or
egForm.Errors depending on the result.

If anyone has time to try it out and give some feedback on the
direction, you can install GoForms with `goinstall
launchpad.net/goforms` or browse the source at:

http://bazaar.launchpad.net/~michael.nelson/goforms/trunk/files

(fields_test.go and forms_test.go have examples - thanks Gustavo for
gocheck :) ).

It's been a great little learning project for me so far.

Cheers,
Michael

--
-
Michael Nelson
http://liveandletlearn.net

http://micknelson.wordpress.com/

Babu Sreekanth

unread,
May 17, 2011, 7:29:43 PM5/17/11
to golang-nuts
Michael,
thanks for your effort on this. As part of my learning of golang, I
too did a part on form generation, validation against domain model,
and highlighting error field upon validation etc. It is on the line
Kyle mentioned earlier in this thread. It is not much of code, but I
was bit overwhelmed by all the options form fields has (html5
especially). Also, I kinda stopped working on it, as it may suitable
for a CRUD admin page but once you start customizing your UI you will
be leaning more towards templates. I could share my code, but I don't
have any test cases and lot more work to do for it being useful. Since
you are experienced with web frameworks, it may easier for you to make
your project useful in more generic context. I was aiming at this
flow.

1. Render a create form --> from an empty struct Person{} , reflect
through each field and generate the markup
2. Parse & validate the form
3. Any error display the fields highlighted
4. Validate the parsed form (or domain object) against domain
validation requirements
5. Any error display the fields highlighted, and error messages
7. ...

As Kyle mentioned, customization of the form and making it play nicely
with template package would be ideal. Since I am not a power user, I
am not in a position to suggest anything about it.
thanks,
Babu.

On May 17, 5:28 pm, Michael Nelson <absolud...@gmail.com> wrote:

Kyle Lemons

unread,
May 17, 2011, 8:34:32 PM5/17/11
to Babu Sreekanth, golang-nuts
> As Kyle mentioned, customization of the form and making it play nicely
> with template package would be ideal. Since I am not a power user, I
> am not in a position to suggest anything about it.
> thanks,
> Babu.

My brain has been thinking about this quite a bit, and I may take a
stab at it too at some point. One interesting, possibly useful, thing
to do would be to use reflection in the formatter of a template
argument to automatically create form elements. For example:

<form ...>
{Name|formString}
{University|formSelect}
{Password|formPassword}
</form>

It looks pretty ugly; better names could probably be chosen. These
can (would? should?) complement a mechanism for reading form data from
the request into the structure. This sort of mechanism could help
close the gap between writing forms and writing the code that
processes them; it would make it trivial to validate form data on the
Go side and just redisplay the form if it's wrong, because the data
and its representation are coupled.

Just some musings. I don't know if I have yet stumbled on the "right"
way to do this, but I think it is a worthwhile conversation to have,
so that maybe a "canonical" way, or a "go-like" way of doing it can
emerge and maybe be integrated into GAE.

Brian Ketelsen

unread,
May 17, 2011, 11:35:20 PM5/17/11
to golang-nuts

On May 17, 2011, at 8:34 PM, Kyle Lemons wrote:
>>
>
> My brain has been thinking about this quite a bit, and I may take a
> stab at it too at some point. One interesting, possibly useful, thing
> to do would be to use reflection in the formatter of a template
> argument to automatically create form elements. For example:
>
> <form ...>
> {Name|formString}
> {University|formSelect}
> {Password|formPassword}
> </form>
>

This looks really nice from the template perspective. It's very clean.

Brian

Michael Nelson

unread,
May 18, 2011, 12:15:07 AM5/18/11
to Babu Sreekanth, golang-nuts
Hi Babu,

Yes, form generation would be a huge job (something similar to
Django's modelforms + widget library etc.). I am interested to see the
approach you took for the validation/error display though, if you get
a chance to put it up somewhere?

Personally, I think it makes sense to keep the form API (definition,
validation and cleaning of data) separate from helpers for generating
forms automatically (similar to Django's model forms, and the link
provided earlier by Islan has a nice example of an approach for
parsing results from an interface).

Similarly for the default rendering of html widgets for each form
field - integration with a (separate) widget library that handles that
would be nice... from what you've said, it sounds like your code
handles this aspect? Let me know if you do make it available
somewhere, as I'd be keen to see the approach you took. I might try
adding a small widget library to the goforms above to try out a few
approaches.

Thanks!

http://micknelson.wordpress.com/

Babu Sreekanth

unread,
May 18, 2011, 7:50:18 AM5/18/11
to golang-nuts
Michael.. please see the code here https://gist.github.com/978407

little bit of explanation

1. Create a form (one of the below)
---------------------------------
f := web.NewForm(Address{}) //create a form
f := web.NewForm(a)} //create a form with value of a filled in (may be
for an edit form)
f := web.NewForm(Address{}, "Zip") //create a form excluding the
'Zip' field
f := web.NewForm(Address{}, "Zip", "Zip2") //create a form excluding
the 'Zip', 'Zip' fields

2. Optional modifications
--------------------------
f.SetOptionField (filedName, optionList, preserve) //render the input
as select field, and set the option values . Preserve set the previous
selection as selected (handy when there was an error, and should not
reset the form)
f.MapValidation( validationObject) // set the error fields and
messages. The validationObject is created at the domain
f.SetRenderType (fn string, rt int, fop FieldAttr) // set the render
type fn--> fieldName, rt --> render type, fop --> field options
//this is handy to custom set render type , textarea instead of text,
readonly, hidden etc ...

3.Render the form
----------------
f.Render() //Finally, render the form in text

NewView // This is not for an input form, but to display the object
(typically Show/Display view)

Excited to see that you have good understanding of Django, and other
framework. Hopefully I could use ur project soon :-)
Reply all
Reply to author
Forward
0 new messages