I've been working on something almost identical to this. But your formconfig is what really gives it that last piece that I didn't have, very nice!
I doubt that it's helpful, but I just put my code up at: https://github.com/bunchesofdonald/django_amaro it's still very early stages, and needs cleaned up, etc. I was just trying for a proof of concept. Let me know if you need another developer and I'll be there, this is one of my biggest pain points with Django. Chris On Jun 23, 2011, at 7:25 AM, Idan Gazit wrote: > At DjangoCon Europe 2011, Gregor Müllegger gave a great lightning talk about > his work on a revised form rendering API: > > http://www.scribd.com/doc/57270484/Djangocon-EU-2011-Revised-Form-Rendering-Lightning-Talk-by-Gregor-Mullegger > > I sat down with Gregor, Jannis, Russell, Alex, Ericflo, Andrew Godwin, and > many other fine minds at the sprints to think about his proposal and help > refine it. At the risk of starting a bikeshedding war, I'd like to share the > results of the sprints and get some feedback on our proposed approach. > > I'm very pleased with the resulting API. It has one significant wart, but > having chewed on the alternatives, I think there is consensus that this API > represents a good compromise between purity and practical considerations. > > > # Goals > > The existing rendering facilities for forms aren't bad, but they suffer from > the following drawbacks: > > 1. All-or-nothing: if you'd like to customize one small part of form > rendering, you have to go the whole hog and write out a ton of boilerplate. > 2. "Frontend developers need not apply": large parts of form rendering happen > in Python. If a frontend dev wants to customize certain aspects of > form.as_p's output, they've got to bust out the python. > 3. Prevents modularity and code re-use: with large bits of markup locked > inside .py files, it's difficult for designers to share reusable form > patterns. > 4. DOCTYPE lock-in: designers are forced to use the XML style of tags, > breaking validation of other doctypes when forms are present. > > The new form rendering API addresses these drawbacks, and as such, has the > following desirable properties: > > 1. No backwards-incompatible changes: the new API coexists peacefully with > the old one, allowing for a smooth transition and deprecation of the old > formrendering API. > 2. Simple beginner usage: if all you're comfortable using is {{ form.as_p }}, > the new API retains a similarly brief approach. > 3. Vastly better customizability: the new API provides an expressive and > flexible means for specifying how forms should be rendered, and allows you to > override just the parts that need changing. > 4. Significant improvements to the rendering of form rows with multiple > fields (for example, first and last name, or credit card and expiration). > 5. Dogfooding: the new API does have some new tags, but a lot of the > internals and examples for customization are just using the existing template > system. This provides a lot of flexibility, but it also means that the new > API should feel familiar to existing developers. > 6. Modularity: it will be possible to produce reusable libraries of form > rendering templates. > > > # The anatomy of form rendering templates > > Forms are composed of three logical units: > > 1. A template which represents the form itself, including some form-specific > configuration. > 2. A template which represents a given "row" in a form. A row is an abstract > concept, and doesn't have to represent a horizontal slice of anything (but > usually does). The existing form rendering API produces rows in the shape of > <p>'s, <li>'s, and <tr>'s. In the new form rendering API, Django supplies the > formrow templates for all three of these row "types", but users can easily > add new ones of these to create a formrow based on <div>'s, for example. > 3. A template which represents a given widget in the form. These are the > widgets which are currently provided by the framework, but supplied as > templates instead of being buried in widgets.py. > > # Examples. > I've prepared example templates for each of these; check out > https://github.com/idangazit/formrendering after reading the following > tutorial. These represent a good starting point for developing the form > templates distributed with Django. > > # API Usage Tutorial > > The new API introduces the following template tags: > > - form > - formconfig > - formrow > - formfield > > For the following examples, "myform" is a form instance present in the > template's context. > > # {% form %} > > The new form rendering API introduces a {% form %} tag: > > {% form myform %} {# equivalent to the following line #} > {% form myform using "forms/layouts/table.html" %} > {% form myform using "forms/layouts/p.html" %} > {% form myform using "forms/layouts/ul.html" %} > > In its simplest incarnation, it works like the existing form.as_XX methods. > Users select a row type by means of the optional using argument. Django will > need to supply the existing row types (table, p, ul) to ease the transition. > > Users can specify their own form templates using the same syntax: > > {% form myform using "fancy_div.html" %} > {% form myotherform using "fancy_div.html" %} > > Like the include tag, form can pass context into its child template: > > {% form myform using "myform.html" with greeting="Hi!" %} > {% form myform using "myform.html" with greeting="Hi!" only %} > > The form tag can also load a configuration inline, as follows: > > {% form myform using %} > ... layout goes here ... > {% endform %} > > The template contents that go inside a form block are identical to those that > can be included from an external template file, as in the previous examples. > > The form tag has one more trick up its sleeve: it can take multiple forms as > an argument: > > {% form myform1 myform2 using "forms/layouts/p.html" %} > > # Form Templates > > In the Django-supplied templates, these would be rendered sequentially, with > form errors at the top of every form. However, users can write their own form > templates which might mix fields from each form, and group both forms' errors > at the top. > > The standard form layouts have a lot of commonality, and so they rely on > template inheritance for DRYness: > > > https://github.com/idangazit/formrendering/blob/master/forms/layouts/layout_base.html#L13-14 > https://github.com/idangazit/formrendering/blob/master/forms/layouts/p.html > > Form layout templates are in the business of spitting out all of the fields > in a form, one row at a time. This is usually accomplished with the {% > formrow %} tag. > > ## {% formrow %} > > The formrow tag is responsible for producing a form's row, and is only valid > within the scope of a form tag. The formrow tag takes an optional template. > If a template is not specified, the default is used (table). Changing the > template to produce <p>'s is accomplished thusly: > > {% for field in form %} > {% formrow field using "forms/rows/p.html%} > {% endfor %} > > Formrow, like form, can take multiple fields: > > {% formrow firstname lastname using "myfancynamerow.html" %} > > Django supplies the formrow templates for table, ul, and p. Like the form > layout templates, they utilize inheritance to keep things DRY: > > > https://github.com/idangazit/formrendering/blob/master/forms/rows/row_base.html > https://github.com/idangazit/formrendering/blob/master/forms/rows/p.html > > https://github.com/idangazit/formrendering/blob/master/forms/rows/hidden.html > > Each form row is responsible for rendering the fields passed to it. > > ## {% formfield %} > > The formfield tag provides the ability to customize widget rendering for one > or more fields. Usually, they are used in the context of a formrow template: > > > https://github.com/idangazit/formrendering/blob/master/forms/rows/row_base.html#L11 > > The field templates are a replacement for the HTML currently buried in the > render() methods of forms/widgets.py. Instead of building the HTML strings in > python, widgets.py should avail itself of the templates to produce its output. > > The default usage of the tag will automatically select a relevant widget > using the existing heuristics. Assuming a form with a CharField named > "first_name": > > {% formfield first_name %} > > Will produce an <input> with the relevant properties. > > If customization is desired, users can write their own widget templates: > > {% formfield publish_date using "mywidgets/fancydatetimepicker.html" %} > > Bruno Renié's django-floppyforms > (https://github.com/brutasse/django-floppyforms) is a lovely example of the > kinds of things accomplishable with template-based form widgets. > > # Controlling default form rendering behavior > > Often, overriding a specific bit of form rendering behavior is desirable. For > example: > > - You want to use a different widget for one specific field in your form. > - You want to use a different widget for all fields of a specific type in > your form. > - You want to specify a different default row style for some or all fields in > a form. > > To that end, there is the {% formconfig %} tag. It is only valid inside a {% > form %} block (or when pulled in via a form layout template). It affects form > state, and as such represents the one part of this proposal that I'm not > entirely happy with. That being said, I like all of its other properties, and > couldn't think of something better which didn't simply shunt the complexity > to another location. > > The formconfig tag is multimodal: the first argument indicates which behavior > to configure. If desired, new modes can be added in the future, and template > designers need not hunt around the docs for new configuration arguments; > they'd be grouped together under the {% form %} reference documentation. > > As shipped with Django, formconfig can operate on widgets and rows: > > {% formconfig widget widgets.Textarea for "comment" %} > {% formconfig row using "forms/rows/ul.html" %} > > The first statement instructs the form to use a textarea widget for any > formfield named "comment." The second instructs the form to use ul's as the > default formrow template anytime a {% formrow field %} is encountered. > > These statements affect global state within a form, and can be reconfigured > multiple times within a form layout: > > {% formconfig row using "forms/rows/p.html" %} > {% formrow field1 %} > {% formrow field2 %} > {% formconfig row using "myrows/fancydiv.html" %} > {% formrow field3 %} > > Similarly, default widgets can be set and reset: > > {% formconfig widget widgets.TextArea for forms.CharField %} > {% formrow bio %} > {% formrow interests %} > {% formconfig widget widgets.TextInput for forms.CharField %} > {% formrow hometown %} > {% formrow zodiac_sign %} > > > # Conclusion > > Hopefully, this proposal will stimulate discussion about how best to > architect the form rendering API. I'd love to see more opinion from more > frontend developers; if you have access to such people, please get them to > check this out and weigh in. > > Don't forget to take a look at https://github.com/idangazit/formrendering, > the templates are a helpful illustration of the possibilities. > > # Also, I want a pony > > This might be a good opportunity to change something I've long considered > very un-Django-like in Django. Form rendering defaults to using tables for > layout, which is semantically icky. How about we make the new default be p, > or better yet, div? To that end, I've supplied div form layout & row > templates. > > > > -- > You received this message because you are subscribed to the Google Groups > "Django developers" group. > To view this discussion on the web visit > https://groups.google.com/d/msg/django-developers/-/LHX20vQru2sJ. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/django-developers?hl=en. -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
