++++++++++++++++++++++++++++++++++++++++++++++++++++ FormEncode, a validation and form generation package ++++++++++++++++++++++++++++++++++++++++++++++++++++ *a system for validation and conversion of input* .. contents:: Summary ======= This presentation describes the FormEncode (formencode.org) validation and form generation package. FormEncode is designed to be both complete in its role, while avoiding excessive frameworkification. It provides significant features not found in most form packages, but does not force the user/programmer to use a particular MVC model, configuration scheme, or generally adopt the original author's worldview. Some of the features: validates rich structures (lists and dicts), both individual members and as a whole; loose coupling between validation, form generation, and domain objects; no static configuration; arbitrary nesting of structures and forms possible; framework neutral. The presentation consists of a brief introduction (goals), and short examples used as a centerpoint for a discussion of the design choices. Metadata ======== Ian Bicking 4869 N. Talman Ave. Chicago, IL 60625 773-275-7241 ianb@colorstudy.com http://blog.ianbicking.org Timeslot: probably 30 minutes (keeping it brief and exciting! Very brief means very exciting! Or 60 minutes...) Background: Ian Bicking is a web developer. He is the author and maintainer of SQLObject_ and PyLogo_, as well as a maintainer of Webware_. .. _SQLObject: http://sqlobject.org .. _PyLogo: http://pylogo.org .. _Webware: http://webware.sf.net Presentation Summary ==================== FormEncode_ is a system for validation and conversion of input, as well as creating web-based forms based on these validation schemas. .. FormEncode: http://formencode.org Several packages exist in the Python world to do form validation and generation. Most of these are specific to a single framework, and have a wide variety of interfaces and featuresets. FormEncode has several features which set it apart: * Complex structures can be meaningfully validated; dictionaries and lists can be validated on a per-member level, with multiple levels of nesting. * Schemas and validators can be easily reused, recombined, and generally manipulated. * Expressive techniques for defining your validation and conversion schemas. * Loose coupling between validation, form generation, and the larger framework and application. * Use of interfaces and adaptation (using the PyProtocols_ package) so that objects can provide multiple features (e.g., validation and form generation), with varying levels of customization. * Generated forms can scale from very simple (mostly auto-generated with little formatting), to highly customized. * All data represented as Python objects, typically as Python class definitions. No static data structures (like XML configuration files) are used. There still exists the possibility to create these Python objects from static data if desired. For example, a schema could be created from database introspection. * Hooks are provided between validation and your larger application to allow context-sensitive validation/conversion. * Validation can occur at all levels, so that consistency among fields can be ensured (e.g., password and password confirmation match, only 10 items allowed in a list, etc). * Framework neutral. FormEncode operates primarily on native Python data structures like dictionaries, lists, strings, numbers, etc. * Imperative in style; FormEncode doesn't take over your application. It doesn't imply any particular object model or application flow. .. _PyProtocols: http://peak.telecommunity.com/PyProtocols.html One of FormEncode's most important design concepts is the simplification of the validation interface. Most form packages have the concept of a *form* and *fields* -- FormEncode simply deals with values. A "form" is a dictionary, a "field" isn't. Unification is accomplished through the use of *compound validators*. These are validators which call on other (sub-) validators. For instance the ``Schema`` validator contains a dictionary of sub-validators; it applies these validators to values from its dictionary input. The ``ForEach`` validator takes a list and applies its validator to each item of that list, and so on. ``ForEach`` validators can contain a ``Schema`` and vice versa, just like a dictionary can contain a list or vice versa. Outline ======= * Introducing me. ("Hi, I'm me") * History (FunFormKit_); describe previous efforts, and the problems with those efforts. Some of what lead to a rewrite. * Design goals: * Avoid coupling. Describe the use of interfaces and adapters (describe the concept of interfaces and adapters in this context? Probably not enough time), how they can be used to provide multiple personalities for an object (important to us: the validation personality and the form personality) * Quick prototyping. Avoid boilerplate, made default behavior reasonably functional. (these are covered more in the examples) * Does not exclude later fine-grained refinement. * Doesn't take over control flow. Has an imperative interface, and doesn't hook into the framework at all. * Examples: (I'm not sure how best to do these, as the body of the presentation is embedded in the examples, but the examples can be lengthy to present, despite their short code length... depending on the time slot it may make sense to use these examples as asides to a more narrative description of FormEncode's features and design principals) * Edit an address: * Define a validation scheme (8 lines + import) * Define form fields and layout (edit those 8 lines, add one line) * Hook it into a simple web application (~10 more lines) * Compound forms: * Name + multiple addresses (using above example) (3 more lines, ~5 more lines in the application). * Use the validation with XMLRPC (~10 more application lines) * Tie the validation into a object/class (in this example a SQLObject_ class for addresses) (12 lines for SQLObject, validation schema expressed inline, retarget application to SQLObject backend). * Conclusion: "I've run over time, so I won't be able to finish the examples." .. _FunFormKit: http://funformkit.sf.net .. _SQLObject: http://sqlobject.org .. _formencode: http://formencode.org