Hi Carl,

On Tue, 18 Mar 2014, Carl Meyer wrote:
On 03/18/2014 02:54 PM, Chris Wilson wrote:

1. GCBV and Vanilla Views do a great job for simple forms, but they
leave out embedded formsets entirely. (For example our large form has
repeating sections for employment history, education, etc.) It feels
like it would be great to have formsets handled "more automatically" -
instantiating, validating and saving them just like we do for forms. A
lot of our code is shared between all our formsets, and potentially
reusable.

The approach I've used for this is encapsulating the creation and
handling of the inline formsets entirely within the "parent" form class,
so from the perspective of the view it acts like a normal simple form.

That seems like an excellent idea, thanks! I'm reworking my forms to work this way.

This requires overrides of a few methods on the parent form: __init__()
to create the formsets, is_valid() to ensure the formsets are valid too,
has_changed() to see if formsets have changed, and save() to save
formsets too.

There's a few more Form methods that I'm not sure whether I need to override, especially if I want to be able to generalise this. I think just _get_media and is_multipart should take sub-formsets into account?

If we were going to look at incorporating something into Django, I'd
like to consider this option as an alternative to adding more GCBVs with
inline-formset support. I think it's a nicer abstraction (because in a
real sense those inlines are "part of" the parent form), and I don't
think we want to add to the already-extensive list of GCBVs and mixin
classes.

I agree. Then it should also work for Vanilla Views with no changes.

I think either approach would be workable as a third-party project, too.

I think it would be nice for forms to be able to treat embedded formsets as a special (complex) type of 'field', so that as_table, as_p etc. would render the formsets as well, and for ModelForm to be able to generate these automatically for models with ForeignKeys that link back to the ModelForm's Model.

2. Adding instances to a formset on the client side using Javascript.
There is a django-formset-js package on PyPI, but it requires special
attributes to be added to form elements that would have been difficult
with crispy forms (which we're also using) and it feels almost like this
functionality ought to be in Django core (maybe not today, but one day?)

I've used this: http://plugins.jquery.com/django-superformset/

Thanks for the tip, I didn't know about that one.

3. We couldn't change the "extra" of a formset without redefining the
formset class. We wanted to do this because the required repeating
sections (employment history etc.) must not have a blank form in them if
they already have some valid forms, otherwise the blank forms prevent
the form being submitted because HTML5 client-side validation fails. So
we had to do all this:

I don't understand this. The 'extra' attribute of a formset class can be
tweaked dynamically as a normal attribute (although this may not be
documented); it doesn't require recreating the entire formset class.

I'm not sure that's possible, because inline_formset defines a new class. That class has a class attribute called 'extra' containing the value of 'extra', but changing it would change it for all instances of the class, so it's not thread-safe. And when the class is instantiated, the value is immediately used to create the initial empty forms, and not used after that, so changing it after instantiating the form has no effect. Thus, it seems that we have to subclass BaseFormSet anyway to get into the constructor and change the value of extra before the initial forms are created.

I snipped your last three items, regarding saving invalid forms. I think this is an unusual use case, and I'm not sure support for it belongs in core. It would be interesting to experiment with something to make filefields less painful when validation fails, but that can be a third-party project first I think.

It may be unusual, but I'm not the only one to want this. At least two people participated on this SO question:
http://stackoverflow.com/questions/8993749/transform-an-unbound-form-to-a-bound-one

From there I got my current approach, which is to use model_to_dict to
create a fake 'data' to make the unbound form bound, so that I can validate it. However this is ugly, and it doesn't work with formsets because it doesn't account for the management form, which complains about having been tampered with because its data is missing. And there's no form_to_dict equivalent of model_to_dict, so I'd have to hack something up, all to pretend to Django that I've got an unbound form, just so I can validate its contents.

Another approach to validating an unbound form appears to be to extract "value" from the model instance instead of cleaned_data, and this bypasses the management form issue, so I'm experimenting with that approach.

It seems to me that there would be value in being officially able to validate unbound forms, and it might not be hard to implement.

Cheers, Chris.
--
Aptivate | http://www.aptivate.org | Phone: +44 1223 967 838
Citylife House, Sturton Street, Cambridge, CB1 2QF, UK

Aptivate is a not-for-profit company registered in England and Wales
with company number 04980791.

--
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.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/alpine.OSX.2.00.1403191201360.13253%40chris-macbook.lan.
For more options, visit https://groups.google.com/d/optout.

Reply via email to