Yuji 'Tomita' Tomita's solution is the acutally best you will find, but assuming you have a multiple step form and you use the django-formtools app you will have some issues you will have to take care of. Thank you Yuji 'Tomita' Tomita, you helped me a lot :)
forms.py
class LicmodelForm1(forms.Form):
othercolumsvalue = forms.IntegerField(min_value=0, initial=0)
class LicmodelForm2(forms.Form):
def __init__(self, *args, **kwargs):
extra_fields = kwargs.pop('extra', 0)
super(LicmodelForm2, self).__init__(*args, **kwargs)
for index in range(int(extra_fields)):
# generate extra fields in the number specified via extra_fields
self.fields['othercolums_{index}'.format(index=index)] = \
forms.CharField()
self.fields['othercolums_{index}_nullable'.format(index=index)] = \
forms.BooleanField(required=False)
For a multiple-step form, you will not need the extra field, in this code we use othercolumsvalue field in the first-step.
views.py
class MyFormTool(SessionWizardView):
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
def get_context_data(self, form, **kwargs):
context = super(MyFormTool, self).get_context_data(form=form, **kwargs)
data_step1 = self.get_cleaned_data_for_step('step1')
if self.steps.current == 'step2':
#prepare tableparts for the needLists
needList_counter = 0
for i in self.wellKnownColums:
if data_step1[i] is True:
needList_counter = needList_counter + 1
pass
#prepare tableparts for othercolums
othercolums_count = []
for i in range(0, data_step1['othercolumsvalue']):
othercolums_count.append(str(i))
context.update({'step1': data_step1})
context.update({'othercolums_count': othercolums_count})
return context
def get_form(self, step=None, data=None, files=None):
form = super(MyFormTool, self).get_form(step, data, files)
if step is None:
step = self.steps.current
if step == 'step2':
data = self.get_cleaned_data_for_step('step1')
if data['othercolumsvalue'] is not 0:
form = LicmodelForm2(self.request.POST,
extra=data['othercolumsvalue'])
return form
def done(self, form_list, **kwargs):
print('done')
return render(self.request, 'formtools_done.html', {
'form_data' : [form.cleaned_data for form in form_list],
})
By overriding the get_form() and get_context_data() functions you can override the form befor it gets rendered. You will not need JavaScript anymore either for your template-file:
{% if step1.othercolumsvalue > 0 %}
<tr>
<th>Checkbox</th>
<th>Columname</th>
</tr>
{% for i in othercolums_count %}
<tr>
<td><center><input type="checkbox" name="othercolums_{{ i }}_nullable" id="id_othercolums_{{ i }}_nullable" /></center></td>
<td><center><input type="text" name="othercolums_{{ i }}" required id="id_othercolums_{{ i }}" /></center></td>
</tr>
{% endfor %}
{% endif %}
The fields from step2 the were made dynamically were also reconized from the formtools because of the same name. But to get there you will have to work around the for-each template loops as you can see:
from the get_context_data()-function
othercolums_count = []
for i in range(0, data_step1['othercolumsvalue']):
othercolums_count.append(str(i))