Looking Back at FormBuild Circa 2006 Archived Pages



This was the FormBuild website aimed at developers. The content is taken from the site's 2006 archived pages. Remember FormBuild, as presented here was considered a beta software that might have some potential glitches that would need working out.
Consider the information you now find here from a historical perspective.

~~~

"My brother, a computer geek, was thrilled when I shared my latest venture with him. Although he knows I'm not into coding, he was surprised and impressed by my enthusiasm for FormBuild. He jokingly compares me to Superman, saying that with FormBuild, I have the power to create HTML forms with ease, much like how Superman effortlessly saves the day. This comparison might seem exaggerated, but for someone like me, who's more into creative projects than technical ones, having a tool that simplifies form creation feels like a superpower. BTW my bro gave me a Superman t shirt for my birthday, which I now wear whenever using FormBuild. I'm excited to explore and rebuild this site, giving it a new life and purpose. So for all the coding enthusiasts out there, enjoy. You'll appreciate the potential of FormBuild, just as I have, finding it a powerful ally in web development." Pete Nicks

 

FormBuild Circa 2006

FormBuild is a package designed to help with the generation of HTML forms. It does not deal with form validation or conversion which are handled excellently by FormEncode which FormBuild is designed to complement.

Status

FormBuild is to be considered beta software. The APIs have not yet had widespread use so there may be one or two problems lurking or areas spotted where the APIs could be simplified further.

Users of 0.1.5b should upgrade to 0.1.6b to fix a bug in formbuild.handle() which had a security problem.

Background and Motivation

There are a number of approaches to take when designing the form handling components of a web application.

  1. Code the forms in HTML, write the validation by hand and write SQL to store and retrieve data from the database.
  2. Model a form field, validation object and database field as the same thing, create specific field objects for each data type your application needs and create one definition for each form that serves as the database structure definition validation object and form handling code all in one.

The first approach is fine for simple applications but leads to a lot of duplication of effort for any project consisting of more than a few forms.

The second approach is brilliant for certain applications where field objects already exist for the data types you wish to handle and you don't want to do anything clever or complicated with a database. If this is the case you only need to define your fields and the application is virtually written. This is the approach Django takes.

The drawback is that you have to unravel a lot of carefully crafted code if you want to do anything more complicated than the system was designed for and this can be very difficult.

The optimum solution for form and database handling has to be that you create form layouts in templates with an API that can be modified to affect the rendering of your forms. Form data is validated with a validation API that is separate from the form layout and form rendering code (after all a form layout is not the same as the values the form contains) and this data is then saved to the database in whatever place is appropriate (after all the data contained in a single form might be stored in more than one table in a database).

Luckily FormEncode already exists to provide a brilliant validation API and SQLAlchemy exists to provide first-class database handling. FormBuild fills the gap to provide form generation tools and the handling glue to handle forms.

Future

Even the FormBuild approach may contain some unnecessary duplication. For example if your SQLAlchemy table definition contains an integer field why not automatically create a FormEncode schema with an Int validator and a FormBuild form with a text box field for input?

Well, this may well be a valid argument and FormBuild has creator objects to help with just such a task although none have yet been written for the example above.

Perhaps once FormBuild has been used more extensively it will become more obvious if this sort of tool would be a genuine benefit or simply a gimmick. So far the Pylons team have made various attempts at a useful CRUD type system (see ContentStor and the more recent Scaffold code) but have come to the conclusion each time that such solutions limit flexibility and in reality don't offer huge advantages for developers.

Please note: FormBuild is not part of Pylons and although it works well with Pylons, is not the only solution available for building forms. The author of FormBuild is also currently looking into the possibility of modifying the TurboGears widgets code for use with Pylons.

Current features:

  • Generation of HTML form components
  • Ability to easily build forms in multiple pages and sections
  • Separation of field and layouts
  • Ability to easily change how existing forms are displayed by customising metaclasses

Documentation

For users:

  • Background and Motivation
  • Getting Started Manual
  • Module Reference
  • Using Pylons with FormBuild
  • Community
  • Download

Author

James Gardner james at pythonweb.org

Credits

Thanks go to Ben Bangert for his ideas.

Development sponsored by 3aims Web Development.

 

FormBuild

WARNING. This site describes FormBuild 1. FormBuild 2 described in the Pylons Book is siginificantly different.

Please note: FormBuild is not part of Pylons and although it works well with Pylons, is not the only solution available for building forms. The author of FormBuild is also currently looking into the possibility of modifying the TurboGears widgets code for use with Pylons.

Current features:

  • Generation of HTML form components
  • Ability to easily build forms in multiple pages and sections
  • Separation of field and layouts
  • Ability to easily change how existing forms are displayed by customising metaclasses

Documentation

For users:

  • Background and Motivation
  • Getting Started Manual
  • Module Reference
  • Using Pylons with FormBuild
  • Community
  • Download

Status

FormBuild is to be considered beta software. The APIs have not yet had widespread use so there may be one or two problems lurking or areas spotted where the APIs could be simplified further.

Author

James Gardner james at pythonweb.org

Credits

Thanks go to Ben Bangert for his ideas.

Development sponsored by 3aims Web Development.

 

Manual

The FormBuild architecture is fairly straightforward. There are four types of components:

  • Forms
  • Builders
  • Modifiers
  • Creators

To use FormBuild you create a form which has a number of attributes. Each of these attributes is in fact a builder object. Builder objects have methods which build part of a form. Then there are modifiers which intercept builder method calls and return other values. Finally creators take some sort of input and create a form.

Forms

Using Fields

At its simplest you can generate fields using FormBuild by creating a form and calling its field methods as follows:

 
  1. >>> from formbuild import Form  
  2. >>> form = Form()  
  3. >>> print form.field.text('hello')  
  4.   

The form object takes the an argument defaults which is a dictionary of name:value pairs used as follows:

  1. >>> from formbuild import Form  
  2. >>> form = Form(defaults={'hello':'Hello World!'})  
  3. >>> print form.field.text('hello')  
  4.   

You can override the default value of a field as follows:

  1. >>> from formbuild import Form  
  2. >>> form = Form(defaults={'hello':'Hello World!'})  
  3. >>> print form.field.text('hello', value="Goodbye!")  
  4.   

and also it also takes an argument errors which is a dictionary of name:error_msg pairs used as follows:

  1. >>> from formbuild import Form  
  2. >>> form = Form(  
  3. ...     defaults={'hello':'Goodbye!'},  
  4. ...     errors={'hello':"Not a very friendly greeting!"}  
  5. ... )  
  6. ...  
  7. >>> print form.field.text('hello'), form.get_error('hello')  
  8.  Not a very friendly greeting!  

Both the defaults and errors arguments can also be lists of dictionaries. If this is the case the field name matched in the first dictionary in the list is used. In a real world application the defaults might be obtained from a database or request arguments.

You might also want to create a field with attributes other than name and value. You do this in the same way:

  1. >>> print form.field.text('hello', style="visibility: hidden;", value="Go>")  
  2.   

Also note that in this example the value contained the character > which is an invalid HTML character. This was automatically converted to the correct character HTML entity >.

Using the form and form.field objects you can now easily generate a form:

  1. >>> from formbuild import Form  
  2. >>> form = Form()  
  3. >>> output = form.start(name="test", action="/script.py", method="get") + '\n'  
  4. >>> output += form.field.text('hello') + '\n'  
  5. >>> output += form.field.submit(name="go", value="Go") + '\n'  
  6. >>> output += form.end()  
  7. >>> print output  
  8.   
  9.   
  10.   
  11.   

Fields available in the default form include dropdown(), text(), hidden(), file(), password(), text_area(), check_box(), radio_button() and submit() but the whole point of formbuild is that it is easy to add your own types too.

Using Layouts

In the real world forms like the ones described above aren't too useful. In real life we might want to label the fields, show error messages when the field value isn't valid, split the form into sections or show a description.

A simple way of generating a form is to mix and match Python template code and HTML:

  1. >>> from formbuild import Form  
  2. >>> name_form = Form()  
  3. >>> o = '
    \n'  
  4. >>> o += '
    \n'  
  5. >>> o += '\n'  
  6. >>> o += '    Name:\n'  
  7. >>> o += '    ' + name_form.field.text(name="name") + '\n'  
  8. >>> o += '    ' + name_form.get_error("name") + '\n'  
  9. >>> o += '\n'  
  10. >>> o += '\n'  
  11. >>> o += '    \n'  
  12. >>> o += '    \n'  
  13. >>> o += '    \n'  
  14. >>> o += '\n'  
  15. >>> o += '\n'  
  16. >>> o += '\n'  

You can do the same thing with the form object's layout attribute:

  1. >>> from formbuild import Form  
  2. >>> name_form = Form()  
  3. >>> o += name_form.start(name="test", action="/script.py", method="get") + '\n'  
  4. >>> o += name_form.layout.simple_start() + '\n'  
  5. >>> o += name_form.layout.entry(  
  6. ...     content=name_form.field.text(name="name"),  
  7. ...     name='Name',  
  8. ...     error=name_form.get_error("name")  
  9. ... ) + '\n'  
  10. ...  
  11. >>> o += name_form.layout.entry(content=form.field.submit(name="go", value="Submit")) + '\n'  
  12. >>> o += name_form.layout.simple_end() + '\n'  
  13. >>> o += name_form.end() + '\n'  

You might prefer to use FormBuild layouts in your template instead. Below is the same example using Myghty where anything between <% and %> brackets is executed and the result printed to the browser. Of course, you can use any templating langaue you like such as Cheetah or Kid:

  1. <% name_form.start(name="test", action="/script.py", method="get") %>  
  2. <% name_form.layout.simple_start() %>  
  3. <% name_form.layout.entry(  
  4.     content=name_form.field.text(name="name"),  
  5.     name='Name',  
  6.     error=name_form.get_error("name") ) %>  
  7. <% name_form.layout.entry(content=form.field.submit(name="go", value="Submit")) %>  
  8. <% name_form.layout.simple_end() %>  
  9. <% name_form.end() %>  

All methods produce the following:

  1.   
  2.   
  3.   
  4.     Name:  
  5.       
  6.       
  7.   
  8.   
  9.       
  10.       
  11.       
  12.   
  13.   
  14.   

Creating Your Own Form Types

All forms are in fact derived from FormBase. The definition of Form used at the start of the GettingStarted Guide `_ is itself derived from ``FormBase and looks like this:

  1. >>> from formbuild.form import FormBase  
  2. >>> from formbuild.builder.field.basic import HtmlFields  
  3. >>> from formbuild.builder.layout.basic import HtmlLayout  
  4. >>>  
  5. >>> class Form(FormBase):  
  6. ...     field = HtmlFields()  
  7. ...     layout = HtmlLayout()  
  8. ...  

To create a form object from this form definition we do this:

  1. >>> form = Form()  

Becuase our Form definition specified the attributes field and layout, our form object created from it will also have the attributes .field and .layout.

HtmlFields and HtmlLayout are builder objects and so each have a number of methods to build fields and layouts respectively. You can add your own functionality to a form definition by attactching a different builder objects to other attributes.

Typically the generation of the form demonstrated above would be done some sort of template.

Imagine you have just finished writing all the forms on a website and your client phones and says he or she wants them to be built in CSS not HTML tables. This would ordinarily be a lot of work as you would have to re-write every form but if you have use FormBuild you can simply alter your form definition:

  1. >>> from formbuild.builder.field.basic import HtmlFields  
  2. >>> from formbuild.builder.layout.basic import CssLayout  
  3. >>>  
  4. >>> class Form(FormBase):  
  5. ...     field = HtmlFields()  
  6. ...     layout = CssLayout()  
  7. ...  

All the forms on your site will now be generated in CSS. If you run the example from the last section again it will now generate this CSS code:

  1.   
  2.     
      
  3.         Name:  
  4.     
  
  •     
      
  •           
  •     
  
  •     
      
  •            
  •     

  


  •   
  •     
      
  •            
  •       
  •     
      
  •           
  •       
  •     
      
  •            
  •       

  •   
  •   

If the CSS code isn't to your liking you can create your own builder object by deriving a class from an existing one and using that instead.

Of course you would need to make sure that the appropriate CSS stylesheet was placed in the HTML document generated. The CSS is available from the attribute name_form.layout.css.

What if you already have a CSS class named form-helper-layout-css-entry-field? Well you would need to specify a unique string to prepend to all FormBuild CSS classes so that the name didn't confilct:

  1. >>> class NameForm(Form):  
  2. ...     layouts = CssLayout(css_prepend='unique_name')  
  3. ...  
  4. >>> name_form = NameForm()  

and now all the classes would start with unique_name, for example unique-name-form-helper-layout-css-entry-field.

Choosing a layout template

It is very nice being able to change how a layout is implemented but what about if you want to use a more sophisticated layout altogether? For example, we might want our form in pages, sections, questions and sub-questions, not just as a long list. In this case we use a different layout template.

In the last example we used the simple CSS layout imported from formbuild.layout.simple. This time we might want to use the HTML layout from formbuild.layout.pages:

  1. >>> from formbuild import Form  
  2. >>> from formbuild.builder.layout.pages import HtmlLayout  
  3. ...     layouts = HtmlLayout()  
  4. ...  
  5. >>> form = NameForm()  

This time we can create our form in pages. A simple page might look like this:

  1. <% form.start(name="page1", action="1", method="POST") %>  
  2. <% form.layout.page_start(title="Research Project Details", description=project_details) %>  
  3.     <% form.layout.section_start(title="Project Details") %>  
  4.         <% form.layout.sub_question(form.field.text(name='project_id'), title="Project ID") %>  
  5.         <% form.layout.sub_question(  
  6.             form.field.text_area(name='project_title', cols=40, rows="5"),  
  7.             title="Project Title") %>  
  8.         <% form.layout.sub_question(form.field.text(name='start_date'), title="Start Date") %>  
  9.         <% form.layout.sub_question(form.field.text(name='end _date'), title="End Date") %>  
  10.         <% form.layout.sub_question(form.field.text(name='sponsor'), title="Research Sponsor") %>  
  11.     <% form.layout.section_end() %>  
  12. <% form.layout.page_end() %>  
  13. <% form.field.submit(name='go', value="Next Page >") %>  
  14. <% form.end() %>  

As you can see, the HTML pages layout has different methods such as start_page() which the simple layout template doesn't have.

Combining Layouts

It is possible that you might want to combine layouts. In this case jsut specify more that one layout when you define your class:

  1. >>> from formbuild import Form  
  2. >>> from formbuild.builder.layout import pages  
  3. >>> from formbuild.builder.layout import basic  
  4. ...     layouts = pages.HtmlLayout(), basic.CssLayout()  
  5. ...  
  6. >>> form = NameForm()  

The new form object will have both basic.CssLayout methods and pages.HtmlLayout methods but where there is a method defined by both classes, the first one will be kept. In this case methods in pages.HtmlLayout would override those in basic.CssLayout.

Extra Fields

As well as the basic fields described above, FormBuild allows you to create forms with other sets of fields by defining your own class. For example to use check_box_group() fields you would need to use the formbuild.field.compound.CompoundHTML fields class in your form. You can do this as follows:

  1. >>> from formbuild import Form  
  2. >>> from formbuild.builder.field import basic  
  3. >>> from formbuild.builder.field import compound  
  4. >>> class MyForm(Form):  
  5. ...     field = basic.HtmlFields(), compound.HtmlFields()  
  6. ...  
  7. >>> form = MyForm()  
  8. >>> print form.field.text(name="hello")  
  9.   
  10. >>> print form.field.check_box_group(  
  11. ...     name="test",  
  12. ...     options=[['0','Holly'],['1','Ivy']],  
  13. ...     values=['1']  
  14. ... )  
  15. ...  
  16.  Holly  
  17.  Ivy  

or by specifying align=vert you could arrange a checkbox group into a table vertically:

  1. >>> print form.field.check_box_group(  
  2. ...     name="test",  
  3. ...     options=[[0,'Holly'],['1','Ivy']],  
  4. ...     values=1,  
  5. ...     align='vert',  
  6. ... )  
  7. ...  
  8.  Holly
      
  9.  Ivy
      

Notice how option values are and values don't have to be strings since everything is converted to a string automatically. For completeness here is a radio group formatted in a table:

  1. >>> print form.field.radio_group(  
  2. ...     name="test",  
  3. ...     options=[['0','Holly'],['1','Ivy']],  
  4. ...     value=1,  
  5. ...     align='table'  
  6. ... )  
  7. ...  
  8.   
  9.       
  10.        Holly  
  11.             
  12.        Ivy  
  13.             
  14.         
  15.             
  16.         
  17.             
  18.       
  19.   

Combining builders

What if you had two layout builders that you wanted to use for your form. Say you want multi-section, multi-page layout for your form but wanted a basic layout as part of one of the sections? You would need to combine your builders. You can do this as follows:

  1. >>> from formbuild.builder.field.basic import HtmlFields  
  2. >>> from formbuild.builder.layout import basic  
  3. >>> from formbuild.builder.layout import pages  
  4. >>>  
  5. >>> class Form(FormBase):  
  6. ...     field = HtmlFields()  
  7. ...     layout = pages.HtmlLayout(), basic.HtmlLayout()  
  8. ...  

This time, when you create your form object from the form definition above, the .layout attribute will have all the methods of pages.HtmlLayout and basic.HtmlLayout.

When combining builders in this way, if two builders have the same method name, the first in the list is used in preference to the others.

Behind the scenes, the builders are combined with the formbuild.modifier.Combine modifier.

Builders

All builders are derived from BuilderBase. FormBuild comes with two groups of builders by default, these are field builders and layout builders found in formbuild.builder.field and formbuild.builder.layout respectively.

All field builders are derived from FieldBuilderBase and all layout builders are derived from LayoutBuilderBase. These classes behave slightly differently and so therefore do all their sublasses.

Each class of builder might have multiple templates. For example, their are layout templates for basic layouts and page layouts. These are in formbuild.builder.layout.basic and formbuild.builder.layout.pages respectivly. Within each module there might be many implementations of the builder template. For example, layout.basic has two classes: HtmlLayout and CssLayout.

If you created a new class of builders to be attached to a form attribute in a form definition you would place them as a sub-directory of formbuild/builder/ in the source tree.

All builder class definitions have a .type attribute which contains the full module path to the class. For example. The basic.CssLayout has a .type attribute which contains the string "formbuild.builder.layout.basic.CssLayout".

Field Builders

There are two field builder templates: basic and compound. Basic field builders have methods to generate all the standard HTML fields like input, select, hidden, textarea etc. Compound field builders have methods for checkbox and radio groups combining basic fields.

All fields which accept a single value must have a value argument in the method that builds them, all field types which accept multiple values must have a values arguent.

Layout Builders

Layout builders are fairly similar to field builders but with one twist. When implementing a layout builder you simply implement the _start() and _end() methods and the combined method then already exists. As a result you need to specify any parameters that are used in both the _start()and _end() methods.

As you can see from the examples below the colour argument needs to be in my_layout_end() even though it isn't used. Lets see an example:

  1. >>> from formbuild.builder.layout import LayoutBuilder  
  2. >>> class MyLayout(LayoutBuilder):  
  3. ...  
  4. ...    def my_layout_start(self, colour='#eee'):  
  5. ...         return '
    '%colour  
  6. ...  
  7. ...    def my_layout_end(self, colour='#eee'):  
  8. ...         return '
'  
  • ...  
  • >>> class MyForm(Form):  
  • ...     layout = MyLayout()  
  • ...  
  • >>> form = MyForm()  
  • >>>  
  • >>> # This:  
  • >>> print form.layout.my_layout(  
  • ...     form.field.text(name='address'),  
  • ...     colour='#ccc',  
  • ... )  
  
  • >>>  
  • >>> # Produces the same as this:  
  • >>> a = form.layout.my_layout_start(colour='#ccc')  
  • >>> b = form.field.text(name='address')  
  • >>> c = form.layout.my_layout_end()  
  • >>> print a + b + c  

  

Modifiers

Modifiers are used to change how the methods of the builders work by intercepting the method call between when the method is got from the class and when it is actually called. This is useful in case you want to do something clever to all fields.

Here is an example which intercepts the values of fields and displays them in HTML in the places they would have been in the orginal form. This is useful for showing users a summary once they have submitted data:

  1. >>> from formbuild import Form  
  2. >>> from formbuild.modifier import Frozen  
  3. >>> from formbuild.builder.field.basic import HtmlFields  
  4. >>>  
  5. >>> class NormalForm(Form):  
  6. ...     field = HtmlFields()  
  7. ...  
  8. >>> class FrozenForm(Form):  
  9. ...     field = Frozen(HtmlFields())  
  10. ...  
  11. >>> normal_form = NormalForm(defaults={'one':'1'})  
  12. >>> print normal_form.field.text(name="one")  
  13.   
  14. >>>  
  15. >>> frozen_form = FrozenForm(defaults={'one':'1'})  
  16. >>> print frozen_form.field.text(name="one")  
  17. 1  

As you can see normal form produces the input HTML as expected (the value 1 is from the default values we specified when we created the form) but with the frozen version, the call is intercepted and only the value is returned.

This is useful when you want to display the values the user chose without having to recode your form or its layout.

Other modifiers that can be used include Capture which captures all the options specified in the builder method and addes it to the .captured attribute of the attribute associated with whichever builder you captured.

Continuing the example above:

  1. >>> from formbuild.modifier import Capture  
  2. >>>  
  3. >>> class CaptureForm(Form):  
  4. ...     field = Capture(HtmlFields())  
  5. ...  
  6. >>> capture_form = CaptureForm(defaults={'one':'1'})  
  7. >>> print capture_form.field.text(name="one")  
  8. None  
  9. >>> capture_form.field.captured  
  10. [['formbuild.builder.field.basic.HtmlFields.text', {'name': 'one'}]]  

As you can see, this time no output is produced but the output is captured so that an external program could do something useful with it, perhaps use it as part of a CRUD system. The information captured combines all keyword attributes, parameters and defaults so that calling the builder method of a normal form with the parameters will produce the orginal output:

  1. >>> captured_params = capture_form.field.captured[0][1]  
  2. >>> print normal_form.field.text(**captured_params)  
  3.   

We mentioned earlier that when you combine builder objects by specifying a list of them next to the attributes, you are actually using a Combine modifier. This modifier combines all the other fields but acts itself like a builder. In this way you can chain modifers together:

  1. >>> from formbuild.modifier import Capture, Combine  
  2. >>>  
  3. >>> class CaptureForm(Form):  
  4. ...     field = Capture(Combine(basic.HtmlLayout(), pages.HtmlLayout()))  
  5. ...  

Creators

Creators create forms from some sort of input. The idea is that people can write creators to take input from another source such as a database or XML schema and automatically produces a form from it.

At the moment the only creator written takes the parameters captured by the Capture modifier and applies it to the form object you want to use the data to be built with:

  1. >>> from formbuild.creator import CaptureDataRecreator  
  2. >>> creator = CaptureDataRecreator(Form())  
  3. >>> r = creator.create([['formbuild.builder.field.basic.HtmlFields.text', {'name': 'one'}]])  
  4. >>> print '\n'.join(r)  
  5.   

The CaptureDataRecreator also have a second parameter which is a dictionary where the keys are the combined module and class names of the builders and the values are the parameters to be passed to their __init__() methods.

For example, to set the basic.CssLayout parameters, pass {'formbuild.builder.layout.basic.CssLayout':{css_prepend:'prepend'},} as the init_params argument.

Creators could be used for things like generating a Python representation of the form to be executed.

 



More Background On FormBuild.org

 

FormBuild.org represents an important moment in the evolution of Python web development. First introduced around 2005–2006, FormBuild was designed to simplify one of the most tedious parts of web programming at the time — generating, structuring, and managing HTML forms.
Before widespread adoption of modern frameworks like Django or Flask, web developers often had to hand-code every form and manually handle input validation and database storage. FormBuild sought to change that, introducing a systematic way to build forms programmatically, while keeping presentation, validation, and logic distinct.

Developed by James Gardner and sponsored by 3aims Web Development, the tool was originally distributed as FormBuild 1, later evolving into FormBuild 2, which was discussed in The Pylons Book as an example of reusable form architecture. Though the project never became mainstream, it heavily influenced subsequent frameworks and form-handling libraries that would standardize the separation between form generation, validation, and database mapping.


Ownership and Authorship

FormBuild was written and maintained by James Gardner, a developer known within the early Pylons and TurboGears communities. His work consistently emphasized modular, Pythonic design and open collaboration. The development of FormBuild was sponsored by 3aims Web Development, a small firm that supported open-source projects in the Python ecosystem during the mid-2000s.

Gardner credited Ben Bangert, another influential Python developer and early contributor to Pylons, for key ideas that shaped the framework. The open acknowledgment of peers, along with a permissive licensing model, highlights how FormBuild was part of a broader community effort to make web development more efficient and standardized.


Background and Motivation

In 2006, building web applications was far more fragmented than today. Frameworks were emerging, but none offered a complete solution for form handling. The traditional options were:

  1. Manual coding: Developers wrote raw HTML for every form and hand-crafted the validation and SQL needed to store data. This worked for small projects but quickly became unmanageable.

  2. Overly coupled frameworks: Some early frameworks attempted to generate forms automatically from database schemas, but this often sacrificed flexibility, forcing developers to work within rigid structures.

FormBuild introduced a middle ground. Its philosophy was that form layout, data validation, and database logic should be independent yet compatible. Instead of binding these systems together, FormBuild created a toolkit for assembling and customizing them. Developers could integrate it with FormEncode for validation and SQLAlchemy for database operations, combining each specialized tool without losing control of their code structure.


Beta Status and Early Adoption

FormBuild’s earliest release, version 0.1.5b, was considered beta software. Users were encouraged to upgrade to 0.1.6b to patch a security issue in formbuild.handle(). Even in its initial state, the tool gained recognition among early Pylons developers for its conceptual clarity.

The official documentation emphasized that the APIs were experimental, and users might encounter “areas spotted where the APIs could be simplified further.” Despite this, its foundational ideas—clean abstraction layers, composable components, and customization through inheritance—were remarkably forward-thinking for 2006.


Technical Architecture

FormBuild introduced an elegant four-tier architecture consisting of Forms, Builders, Modifiers, and Creators. Each component played a distinct role in how forms were generated and rendered.

1. Forms

The Form object was the developer’s main interface. A Form contained definitions for fields, layouts, and behavior. Developers could instantiate a form with default values and error dictionaries, allowing dynamic control over input content and validation messages.

For example, a form could be initialized as:

form = Form(defaults={'name': 'Alice'}, errors={'name': 'Required field'})

When rendered, the Form automatically inserted the appropriate HTML and displayed inline error messages.

2. Builders

Builders were responsible for generating the actual HTML markup for fields and layouts. Two primary builder categories existed:

  • Field Builders: Created input fields such as text boxes, checkboxes, dropdowns, and radio groups.

  • Layout Builders: Defined how those fields were displayed — either in tables, CSS-based grids, or multi-page sections.

By swapping out a layout builder, developers could completely change the look of their forms without touching any of the logic.

3. Modifiers

Modifiers intercepted the builder methods to alter how they behaved.
For example:

  • The Frozen modifier replaced editable inputs with static text, useful for showing submitted data back to a user.

  • The Capture modifier logged field definitions for reuse or replication.

  • The Combine modifier allowed multiple builders to coexist, merging their features.

This design pattern gave FormBuild extraordinary flexibility and is still mirrored in many modern frameworks that use middleware or decorators to alter behavior dynamically.

4. Creators

Creators generated new forms based on existing input or metadata.
For instance, one creator could read captured parameters and automatically reproduce a similar form. This feature foreshadowed the auto-form generators that would later appear in frameworks like Django, Flask-WTForms, and FastAPI.


Features and Capabilities

FormBuild’s documentation outlined several important features:

  • Generation of complete HTML form components.

  • Support for multi-page and multi-section form structures.

  • Clear separation between field definitions and their visual layout.

  • Easy customization through subclassing and metaclasses.

  • Dynamic CSS or HTML output depending on developer preference.

  • Support for building forms that used multiple combined layouts or field sets.

  • Automatic escaping of invalid characters (e.g., > to >) to maintain HTML compliance.

  • Built-in mechanisms for error handling and value substitution.

These capabilities made FormBuild a powerful prototype tool — developers could experiment with layout and logic simultaneously while maintaining strict separation of concerns.


Integration with Pylons and FormEncode

Although not officially part of the Pylons framework, FormBuild was designed to work seamlessly with it. Pylons was known for its lightweight and modular approach, which aligned perfectly with FormBuild’s philosophy.

Form validation was handled through FormEncode, another Python library that specialized in schema validation and data conversion. With FormBuild managing layout and FormEncode ensuring input correctness, developers gained full control over the entire form lifecycle without code repetition.

For database operations, SQLAlchemy provided the missing piece — robust ORM functionality. Together, these three tools—FormBuild, FormEncode, and SQLAlchemy—formed a clean, composable workflow that anticipated patterns later adopted by modern frameworks.


Example of Usage and Flexibility

The documentation highlighted a simple but compelling example: suppose a developer wanted to change every form on a website from a table layout to a CSS-based layout. Traditionally this required rewriting all templates. In FormBuild, it was as easy as subclassing and redefining a single line:

class Form(FormBase):
  field = HtmlFields()
  layout = CssLayout()

That one change re-rendered all forms using a CSS grid rather than HTML tables. This separation of logic and presentation, now taken for granted in most frameworks, was quite innovative in 2006.

Developers could also combine layouts, allowing sections of a form to use different display strategies. Multiple builders could be attached to a single form definition, and the framework resolved conflicts by prioritizing the first defined builder method.


Community and Documentation

The FormBuild site included extensive documentation, such as:

  • A Getting Started Guide

  • A Module Reference

  • Using Pylons with FormBuild

  • A Community Section

  • A detailed Manual

These resources were presented with real Python examples and rendered HTML output. The community, though small, was active within the Python web development mailing lists of the time. Many early adopters were also contributors to other open-source Python projects.


User Impressions and Developer Culture

A unique element of the archived pages was a personal note by a user named Pete Nicks, who likened his enthusiasm for FormBuild to “wearing a Superman T-shirt” because of how empowered he felt being able to create complex forms without deep coding knowledge.
That anecdote captures the spirit of early-2000s open-source software: small, tightly knit developer groups building tools that made programming more accessible, while celebrating the empowerment of creativity and control over technology.


Legacy and Influence

FormBuild’s influence extends beyond its direct user base. Even though later frameworks such as Django, Flask-WTForms, and FastAPI overshadowed it, many of its core concepts lived on:

  • Separation of logic and presentation — now standard in nearly all frameworks.

  • Declarative form structures — mirrored in WTForms and Django Forms.

  • Dynamic modification of builders — a precursor to decorator and middleware patterns.

  • Composable validation systems — echoed in modern schema libraries like Pydantic.

By formalizing ideas around “builders” and “modifiers,” FormBuild helped shape the vocabulary and design philosophy of Python web tools that came after it.

The project also demonstrated that smaller independent developers could meaningfully influence the direction of open-source web architecture through modular design and community collaboration.


Cultural and Historical Significance

FormBuild sits at a crossroads in web history — after the CGI era but before the consolidation of large, monolithic frameworks. It embodies the experimentation that defined the Python ecosystem during the mid-2000s, when developers prioritized flexibility over convention.

Its partnership with projects like Pylons and FormEncode showed how open collaboration could create powerful toolchains long before “microservices” or “modular architecture” became buzzwords.
Furthermore, the project’s emphasis on adaptability — easily changing layouts, combining builders, or capturing parameters — anticipated the principles behind later “component-based” web design.

Even though FormBuild eventually became obsolete as frameworks standardized their own form APIs, its historical role remains noteworthy as one of the earliest comprehensive form generation frameworks in Python.


Present-Day Relevance

While FormBuild itself is no longer actively maintained, archived copies of its documentation continue to circulate among Python historians and educators. It remains a valuable teaching example for students studying software design patterns, particularly regarding builder, modifier, and factory patterns.

Developers exploring modern frameworks can still recognize FormBuild’s DNA in the declarative and reusable nature of today’s form libraries. Many of the patterns introduced by FormBuild have become so standard that they are now invisible — absorbed into the collective fabric of Python web development.


 

FormBuild.org stands as a testament to a formative period in open-source web development. Created by James Gardner and sustained by an enthusiastic early-Python community, the project successfully bridged the gap between raw HTML form coding and rigid full-stack frameworks. Its architecture — centered on Forms, Builders, Modifiers, and Creators — anticipated many of the concepts that would later dominate Python’s web ecosystem.

Although time and technology have moved on, FormBuild’s ideas continue to echo through every Python web app that separates form logic from layout, every schema that validates data independently of its presentation, and every developer who values modular design over monolithic constraint.

FormBuild.org may now serve primarily as an archive, but historically it represents a turning point — the moment when developers began to think of forms not as static markup, but as dynamic, composable software components.

 


FormBuild.org