- Author:
- AgustinLado
- Posted:
- October 2, 2014
- Language:
- Python
- Version:
- Not specified
- Score:
- 1 (after 1 ratings)
This is a simple example of feeding multiple Forms into a single Form via its constructor method, to work with a single FormView and reap the benefits of Django's awesome Form validation system. It's a Form class that defines (or takes via an argument to its constructor) parent Forms (that can, for instance, be ModelForms, to take advantage of the automatic Field generation) and takes its fields from there.
An advanced user won't be impressed by this, so excuse if this snippet is out of place, but a rather inexperienced user such as myself might find it interesting and make him willing to explore Django's internals a bit more.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | class ActualForm(forms.Form):
"""
This form's fields are the sum of the fields defined by its parent forms.
By creating this form dynamically I'm able to take advantage of the
ModelForms functionality of automatically setting the Model's fields
while still ending up with a form that comprises multiple models.
The Parent forms are specified in the :attr: parent_forms
or received in the constructor as :arg: parent_forms
"""
parent_forms = [SomeForm1, SomeForm2]
def __init__(self, parent_forms=[], *args, **kwargs):
super(ActualForm, self).__init__(*args, **kwargs)
# If the class was instantiated with a list of parent Forms as
# an argument, use said list. Else look for a hard-coded attribute.
# This line is hilarious.
parent_forms = parent_forms if parent_forms else self.parent_forms
# Make a list of form fields. The list comprehension makes a
# nested list that gets flattened by itertools' chain
form_values = list(itertools.chain(
*[form().fields.iteritems() for form in parent_forms]
))
# Add the values of the parent forms to the actual form
for k, v in form_values:
self.fields[k] = v
# In Views:
class ActualFormView(FormView):
"""
Use the Class Based View as always, but make sure to set
form_class to be the dynamic Form.
"""
form_class = ActualForm
def form_valid(self, form):
# Create objects. Do stuff.
return super(ActualFormView, self).form_valid(form)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
I got confused by an Internal Server Error after posting the snippet and tried again, failing to notice it had already been created. I'm sorry! Delete this duplicate, please.
#
I am a fellow inexperienced user and this saved my life, basically. Thanks for sharing.
Be advised: in Python 3:
form().fields.iteritems()
should be changed to:
form().fields.items()
.#
In the line
super(ActualForm, self).__init__(*args, **kwargs)
I get the following error. TypeError: init() got an unexpected keyword argument 'instance'Other places I've searched about it didn't help. Please help. Django 3.1 Python 3.9
#
Please login first before commenting.