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

2👍

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

http://docs.djangoproject.com/en/dev/topics/forms/formsets/#topics-forms-formsets

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

👤Brant

12👍

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:
http://jacobian.org/writing/dynamic-form-generation/

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.

Edit:

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 %}

2👍

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.

0👍

You may want to try something like this:

form_view.html

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

views.py

# 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

models.py

# 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)

forms.py

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
                products.append(product)
        if commit is True:
            Product.objects.filter(company=company).delete()
            Product.objects.bulk_create(products)
        return company
        

Leave a comment