Ok, dynamic fields. Now we're digging into the dark depths of Django. Not something you can find in the documentation, well me anyway.
There are a few posts online about it but some are fairly old, before the Django "newforms" were introduced. All that means is if you tried that code it won't work.
This example shows us how to:
- Pass an argument to the form upon creation (user variable)
- Dynamically create fields upon creation
- Modify the choices for an existing field upon creation
These should cover the use cases of most dynamic forms.
class ExampleDynamicForm(forms.Form):
normal_field = forms.CharField()
choice_field = forms.CharField(widget = forms.Select(choices = [ ('a', 'A'), ('b', 'B'), ('c', 'C') ]))
def __init__(self, user, *args, **kwargs):
# This should be done before any references to self.fields
super(ExampleDynamicForm, self).__init__(*args, **kwargs)
self.user = user
self.id_list = []
# Some generic loop condition to create the fields
for blah in Blah.objects.for_user(user = self.user):
self.id_list.append(blah.id)
# Create and add the field to the form
field = forms.ChoiceField(label = blah.title, widget = forms.widgets.RadioSelect(), choices = [('accept', 'Accept'), ('decline', 'Decline')])
self.fields["blah_%s" % blah.id] = field
# Change the field options
self.fields['choice_field'].widget.choices = [ ('d', 'D'), ('e', 'E'), ('f', 'F') ]
To use the form:
form = ExampleDynamicForm(request.user)
It may look scary but it's not that bad.
Follow the formula and you'll be fine.
Note: Remember, the super().__init__() call should be made early on before any references to self.fields.