django formtools initial data via GET parameter

377 views Asked by At

I'm using django-formtools to create a form wizard. I want to pre-fill the first part of the form using get-parameter. First I validate the GET data with a regular django form.

form.py

class MiniConfiguratorForm(forms.Form):
    width = forms.IntegerField(min_value=MIN_WIDTH, max_value=MAX_WIDTH, initial=25, label=_('width'))
    height = forms.IntegerField(min_value=MIN_HEIGHT, max_value=MAX_HEIGHT, initial=25, label=_('height'))
    amount = forms.IntegerField(min_value=MIN_QUANTITY, max_value=MAX_QUANTITY, initial=1, label=_('amount'))

class ConfiguratorStep1(forms.Form):
    # ...
    width = forms.IntegerField(widget=forms.NumberInput(), min_value=MIN_WIDTH, max_value=MAX_WIDTH, initial=25, label=_('width'))
    height = forms.IntegerField(widget=forms.NumberInput(), min_value=MIN_HEIGHT, max_value=MAX_HEIGHT, initial=25, label=_('height'))
    amount = forms.IntegerField(widget=forms.NumberInput(), min_value=MIN_QUANTITY, max_value=MAX_QUANTITY, initial=1, label=_('amount'))

class ConfiguratorStep2(forms.Form):
    name = forms.CharField(max_length=100, required=True)
    phone = forms.CharField(max_length=100)
    email = forms.EmailField(required=True)

views.py

class ConfiguratorWizardView(SessionWizardView):
    template_name = "www/configurator/configurator.html"
    form_list = [ConfiguratorStep1, ConfiguratorStep2]

    def done(self, form_list, **kwargs):
        return render(self.request, 'www/configurator/done.html', {
            'form_data': [form.cleaned_data for form in form_list]
        })

    def get(self, request, *args, **kwargs):
        """
        This method handles GET requests.

        If a GET request reaches this point, the wizard assumes that the user
        just starts at the first step or wants to restart the process.
        The data of the wizard will be reset before rendering the first step
        """
        self.storage.reset()
        # reset the current step to the first step.
        self.storage.current_step = self.steps.first

        mini_configurator = MiniConfiguratorForm(data=request.GET)
        init_data = None
        if mini_configurator.is_valid():
            init_data = {
                    'width': '35',
                    'height': '33',
                    'amount': '17',
            }
            print("valid")
        else:
            print("invalid haxx0r")
        return self.render(self.get_form(data=init_data))

My approach was to override get() and to pass the data in self.get_form(data). This does not work correctly. All fields are empty. If i access the form without parameter, the form renders correctly.

1

There are 1 answers

0
lucutzu33 On

From the docs:

Initial data for a wizard’s Form objects can be provided using the optional initial_dict keyword argument. This argument should be a dictionary mapping the steps to dictionaries containing the initial data for each step. The dictionary of initial data will be passed along to the constructor of the step’s Form:

>>> from myapp.forms import ContactForm1, ContactForm2
>>> from myapp.views import ContactWizard
>>> initial = {
...     '0': {'subject': 'Hello', 'sender': '[email protected]'},
...     '1': {'message': 'Hi there!'}
... }
>>> # This example is illustrative only and isn't meant to be run in
>>> # the shell since it requires an HttpRequest to pass to the view.
>>> wiz = ContactWizard.as_view([ContactForm1, ContactForm2], initial_dict=initial)(request)
>>> form1 = wiz.get_form('0')
>>> form2 = wiz.get_form('1')
>>> form1.initial
{'sender': '[email protected]', 'subject': 'Hello'}
>>> form2.initial
{'message': 'Hi there!'}

More info: https://django-formtools.readthedocs.io/en/latest/wizard.html#providing-initial-data-for-the-forms