Hi all,

As far as I'm aware (from browsing the mailinglists and the newforms
code) newforms currently does not support compound or nested forms.
With this I mean something like (fairly dumbed-down example, but taken
from an app I'm currently working on):

class AddressForm(forms.Form):
    street = forms.CharField()
    city = forms.CharField()

class BusinessLocationForm(forms.SuperForm):
    organisation = forms.CharField()
    visiting_address = forms.SubForm(AddressForm)
    postal_address = forms.SubForm(AddressForm, required=False)

Currently I could copy/past the fields of AddressForm directly into
the BusinessLocationForm. Or I'd have to create three separate forms
(using prefixes) in my view and deal with it manually (subclassing
BusinessLocationForm from AddressForm would only help if I'd only have
the need for one address).

In the past I've done some work with FormEncode, and that allows the
exact use-case I've sketched above. That worked well, so I thought,
may be I can add that functionality to newforms.

So currently I've a (more or less working) implementation of what I've
called a SuperForm, which can take either Fields or SubForms as shown
above. The resulting form instance then behaves like any normal form.
Clean_data becomes a dict of dicts so that you can easily take out all
data related to a particular subform. E.g. in the above case you would
get something like:
------------------------------------------------------------------------------------------------------------------
# create form instance
f = BusinessLocationForm()

# render the form, casauses all subforms to be rendered as well
f.as_table()

# the form elements are named as follows (using prefixes)
# organisation
# visiting_address-street
# visiting_address-city
# postal_address-street
# postal_address-city

# have user submit form and ...

# receive data and create bound form
f = BusinessLocationForm(request.POST)

# validate, all subforms are validated as well, unless they're not
required AND empty
# in which case they're ignored
if f.is_valid():
    # assume AddressRecord and BusinessLocation are models closely
matching
    # the presented forms
    # create a address record for visiting_address
    f.clean_data['visiting_address'] =
AddressRecord(f.clean_data['visiting_address'])
    f.clean_data['postal_address'] =
AddressRecord(f.clean_data['postal_address'])
    business_location = BusinessLocation(f.clean_data)
------------------------------------------------------------------------------------
The above example is very dumbed down but I guess you get the idea.
The code after "is_valid" could
perhaps be made more generic and put in a default SuperForm.save
method. But maybe that's trying to be too smart. In any case you could
put it there yourself, just to make the view code cleaner - in which
case you'd just do:

if f.is_valid():
   f.save()

Apart from the SubForm "field" I've also created a FormList "field"
which takes a form definition, a min_count and a max_count which
allows for easy creation of a whole list of identical forms (think
edit_inline=models.STACKED).

The SuperForm class I refer to by the way, is in fact a container for
a number of forms that mimics the behaviour of a normal form. All
subforms are stored in a SortedDict. I've taken a copy of BaseForm and
reimplemented all methods to do the right thing to all subforms. If
you add normal Fields to a SuperForm, those are collected and turned
into another regular Form, which then in turn is added to the dict of
subforms maintained by SuperForm.

Since a SuperForm acts entirely as a normal Form you can also nest
SuperForms. So you could do:
-------------------------------------------------------------------------------------------------
class OrganisationForm(forms.SuperForm):
    name = forms.CharField()
    headquarters = forms.SubForm(BusinessLocationForm)
    other_locations = forms.FormList(BusinessLocationForm,
min_count=1, max_count=10, required=False)

f = OrganisationForm(request.POST)
# clean_data['other_locations'] would be a list
for location_data in f.clean_data['other_locations']:
     location = BusinessLocation(location)
     location.save()
     ...
     ...
-------------------------------------------------------------------------------------------------

My questions now boil down to: Do any of you think of this as a
desirable feature, if so do you agree with the road I've taken? Is
anyone else already working on this?

If there's desire and no objections I'll produce a cleaned up version
and submit it in Trac. That could either be as e.g. contrib.superform
or as a "patch" against newforms - I put "patch" between quotes
because the existing newforms code is not touched in anyway, it's
totally "bolt-on" in the form of a number of new classes.

Rgds,
Jeroen


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@googlegroups.com
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to