I am trying to create a dynamic form, with a varying number of CharFields. I want to be able to display them at will in semi-arbitrary places in my form. My approach was to create an iterable function that fielded the right self.fields[INDEX]. However, when I do this, I literally see this:
<django.forms.fields.CharField object at 0x80bae6be0>
<django.forms.fields.CharField object at 0x80bae6f98>
<django.forms.fields.CharField object at 0x80bae6da0>
How do I make a CharField() render as expected?
My code is below:
class ImplementationForm(forms.ModelForm):
"""
Specifies the implementation of a given control.
"""
class Meta:
model = Implementation
fields = ['implemented', 'scope', 'separate']
def __init__(self, *args, **kwargs):
control = kwargs.pop('control')
super(ImplementationForm, self).__init__(*args, **kwargs)
self.fields['separate'].widget.attrs.update({'class': 'separate'})
self.fields['scope'].widget.attrs.update({'class': 'scope'})
for substatement in control.substatement.all():
self.fields['statement_%s'%substatement.pk] = forms.CharField()
def subfield(self):
print("Comes herE")
for index in self.fields:
if index[:10] == 'statement_':
yield self.fields[index]
The template basically does this:
{% for x in myform.subfield %} {{ x }} {% endfor %}
What you are looking for is the form's BoundFields. e.g. {{ form.email }} You are iterating over the Field instances (not the form's BoundField instances that wraps the Field Instances) e.g. {{ form.field.email }}. This is why you are getting the
<django.forms.fields.CharField object at 0x80bae6da0>
result from your template. See: https://stackoverflow.com/a/671305/3035260
Also see django's documentation: https://docs.djangoproject.com/en/1.10/ref/forms/api/#django.forms.BoundField
Try this dirty way (See my edit below for a much better solution):
{# Iterate over your list of field instances #}
{% for x in myform.subfield %}
{# Find the matching BoundField instance #}
{% for field in myform %}
{% if field.field == x %}
{# Matching BoudField instance found, display it. #}
{{ field }}
{% endif %}
{% endfor %}
{% endfor %}
Edit: Just came across a better (less dirty) approach: A Field has a
get_bound_field(self, form, field_name)
method according to the docs: https://docs.djangoproject.com/en/1.10/_modules/django/forms/fields/#Field.get_bound_field
So, in your subfield method in the last line (The 'yield' line), try this:
yield self.fields[index].get_bound_field(self, index)
Then, your template will remain the same:
{% for x in myform.subfield %} {{ x }} {% endfor %}
and everything should work as you intended.