How to dynamically create form fields on init

Hey,

I’m having a form for selecting some products. The form contains other information, and on init I want to pass it a number of products to generate checkboxes for.


class ProductsForm(Form):

    # ... other fields

    def __init__(self, products, *args, **kwargs):
        super(AddToCartForm).__init__(*args, **kwargs)
        for p in products:
            self.fields[f"product-{p.id}"] = BooleanField()

For this I get "AttributeError: ‘ProductsForm’ object has no attribute ‘fields’.

Django’s BaseForm creates the ‘fields’ from the base_fields, so after the initializing the super class it should be available. Why isn’t it?

And how would I go about adding those dynamic fields?

Best,
J.

Hello there!
The functionality that you’re describing is available on the django admin, where on the changelist page you can select some rows of a table, and then select an action. I think that’s a good starting point for where you can find a similar example on how to approach this scenario. This example is for the situation where you only need to select a row, but if you need to POST some information and then also select the products, you may want to take a look into formsets.
I would say that creating dynamic fields is indeed possible, but its not the ideal way of approaching this scenario.

Why are you initializing a non-existent parent class (AddToCartForm)? Consider the following approach to your problem.

from django import forms

class ProductsForm(forms.Form):
    products = forms.MultipleChoiceField(
        widget=forms.CheckboxSelectMultiple()
    )

    def __init__(self, products, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Assuming products is a list of tuples. e.g. [(key, value), (key2, value2)]
        self.fields["products"].choices = products

Sorry, forgot the class name in the init when I abstracted the code for the question, it would be with the “ProductForm”. But yes, calling just super() without the form class avoids the error message!