[Fixed]-Django: create HTML input array using a django form


It looks like I can do what I need to do by breaking the form into multiple formsets…


Then, I should be able to access each formset individually from the template, wrapping all of them into one



Jacob Kaplan-Moss (co-author of Django) recently posted a great article for handling dynamic forms, which should solve your problem in a preferred way:

He’s using the same method that Felix suggests, but it’s worth reading the whole article to get a better grasp on the concept.

Using the asdf[] technique is sloppy, because then you have to deal with ordering. It’s also not the standard practice.


To handle the situation where you need to detect when you hit these dynamic fields:

{% for input in form.fields %}
    {% ifequal input.label 'asdf' %}
        {{ forloop.counter }}: {{input}}<br />
    {% endifequal %}
{% endfor %}


It should be more like e.g.:

# in a model class
for i in range(1, prim+1):
    self.fields['asdf_%s' % i] = forms.CharField(label='Label %i' % i)

But it very depends on what you want to achieve.


You may want to try something like this:


<!-- simple form page -->
<form action="{{ request.path }}" method="post">
  {{ form }}


# Some form controller
class DynamicFormView(FormView):
   form_class = DynamicForm
   template_name = "form_view.html"

   def get_form_kwargs(self):
        kwargs = super(DynamicFormView, self).get_form_kwargs()
        # Decide on a number of dynamic fields
        # to pass into the form
        # i.e. form(num_products=5)
        kwargs['num_products'] = 5  
        return kwargs


# A model
class Company(models.Model):
    name = models.CharField(max_length=200)

# A model with a many to one relationship with another model
class Product(models.Model):
    company = models.ForeignKey(Company, on_delete=models.CASCADE)
    name = models.CharField(max_length=200)


class DynamicForm(forms.ModelForm):
    product_label = 'Product name'
    class Meta:
        model = MyModel
        fields = ['name']

    def __init__(self, *args, **kwargs):
        # get the number of dynamic fields to create
        num_products = kwargs.pop('num_products')
        # initialize the form before creating fields
        super(DynamicForm, self).__init__(*args, **kwargs)
        # create the dynamic fields
        for row in range(num_products):
            self.fields['product_'.format(row)] = forms.CharField(label=self.question_label)

    def save(self, commit=True):
        # create the default object
        company = super(DynamicForm, self).save(commit)
        # create child products from the dynamic fields
        products = []
        for key, value in self.cleaned_data.items():
            if key.startswith('product_'):
                product = Product()
                product.name = value
                product.company = company
        if commit is True:
        return company

Leave a comment