On 20 Sep 2013, at 9:55, Russell Keith-Magee wrote:
On Fri, Sep 20, 2013 at 2:41 PM, Marc Tamlyn <[email protected]>
wrote:
This is partly because there's no obvious correct implementation of
them ;)
Yes, I think these views should exist. But they go with the same body
of
work as handling multiple forms, inline formsets etc. At present I
have no
yet found the time to think about this problem, as a whole and come
up with
a single consistent solution.
I'm not sure FormSetView *should* exist. I'd be a lot more inclined to
look
at something like FormContainer -- a form-like container that can
contain
multiple forms and formsets. There's a sample implementation on #18830
in
the context of extending FormWizard to support combinations of form
and
formset.
https://code.djangoproject.com/ticket/18830
If you had a form container, you wouldn't need a new generic view --
you
can just use FormView, and use the FormContainer as the form.
(I'd also like to rethink generics in general, but that's a whole
other
conversation… and one that I need to internally progress from vauge
rambling to slightly coherent proposal… and then find time to work
on :-)
Yours,
Russ Magee %-)
+1 on having a way to arbitrarily compose forms and formsets on django's
core.
Having built ways to nest forms and formsets within forms, I'll have to
agree with Andrew that having something like `forms.SubForm(MyForm)` or
`forms.SubFormSet(MyFormSet)` would be a better api than having a
generic view or an abstraction between views and forms (that's what I
assume you mean with FormContainer).
Composing multiple forms or formsets by adding `nested_form =
forms.SubForm(MyForm)` in the form definition seems like a natural
extension of the Form api and presents a lot of benefits:
1. It is apparent to the api user that the parent form would maintain
the same external api. `my_form.is_valid`, `my_form.save` on a
ModelForm, `{{ my_form }}` in the template, etc. would still work and
take into account the nested forms. Having a different object act as a
form/formset container would mean that either the users would have to
learn another api, or that the container would have to mirror the form
api (in which case, it might as well be a form). This also means that
(depending on the use case) you could add sub forms/formsets on your
form and have your view and template code remain unchanged.
2. It also maintains the same internal api, since adding a form/formset
and customising its validation would be the same as adding any other
field. This also allows you to mix regular fields with sub
forms/formsets.
3. It allows arbitrary composition of form/formsets. Since the container
object would be a regular form, it could be used wherever a form could
be used. This means that you could use a form containing a sub
form/formset with formsets, form wizards, generic form views etc.
without having to do any additional work. This would also trivially
solve the formsets-within-formsets problem (my original use case) that a
lot of people seem to be having trouble with (google "django nested
formsets").
4. It opens the road for more intelligent ModelForms. This wouldn't be
done automatically for backwards compatibility reasons, but having a
well defined way to nest sub forms/formsets within forms could be
extended to automatically create them for OneToOneFields and
ManyToManyFields.
Having said all that, there are a few factors that would make the
implementation and usage a bit tricky. In no particular order:
1. The Fields/Widget api is not well suited for `SubForm/Formset`
fields. I could elaborate more on this, but the crux of the problem is
that fields and widgets are used internally in a stateless manner, while
forms and formsets need to keep track of a lot of state. That said, I
think it could be done.
2. It requires modifications of `django.forms.Form` (and potentially of
`django.forms.BoundField`, depending on the template api it would
expose). This means that this couldn't be done in a third-party app as a
proof of concept. My solution has been to create a custom Form subclass
and inherit from it whenever I need the sub form/formset functionality,
but this is incompatible with other apps that require you to inherit
from their custom Form subclass (eg. floppyforms).
3. There are issues with saving sub forms/formsets. Saving an outer form
with `commit=False` cannot really return an object that would save
everything when its `save` method is called, due to the same orm
limitations that has necessitated the `save_m2m` method. The optimal
solution would be to solve this in the orm layer, but I have no idea if
this is feasible. My solution is to create additional `save_forms` and
`save_formsets` methods on the form instance, plus a fourth
`save_related` method that just calls the other 3. The result is that
the form's external api remains similar, but you have to call
`save_related` instead of `save_m2m`.
4. There are lots of moving parts and edge cases in the interactions
between the parent form, the sub form/formset field and the actual
nested form/formset. I'm sure there are a lot of these but here's a
sample of what i've run into:
- should the parent form's prefix be prepended to the child form's
prefix?
- should the form field's name be prepended to the child form's prefix
(to support having the same form nested twice inside a parent form)?
- should `auto_id`, `error_class` and `label_suffix` be propagated to
child forms?
- should `required=False` on the SubForm field be translated to
`empty_permitted=True` on the sub form?
I believe that all of the above have sensible answers but they will
certainly require some thought.
5. This isn't exactly django's problem and it is specific to the
formsets-within-formsets scenario, but things get messy on the
javascript side if you want to be able to add/remove forms client side
with nested formsets.
--
You received this message because you are subscribed to the Google Groups "Django
developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.