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.