Django Form Wizard Skip Multiple Steps with Conditional Logic

972 Views Asked by At

Is there some way to skip multiple steps in Django's Form Wizard (i.e. SessionWizardView)?

I know it is possible to use condition_dict to produce the following form display logic: Page 1 -> Page 3

#urls.py 
path('main/', MyWizard.as_view(set_of_forms, condition_dict={'1': view_condition} ))

What I would like to do is the following: Page 1 --> Page 4

Presumably, adding a condition_dict based on the content of Page 1 should work to skip Page 3, but it doesn't work. For example:

#urls.py 
path('main/', MyWizard.as_view(set_of_forms, condition_dict={'1': view_condition, '2': view_condition2,} ))

I am truly stumped on how to crack this nut. Any guidance that you can provide would be GREATLY appreciated.

2

There are 2 best solutions below

1
AudioBubble On BEST ANSWER

The typical way to specify when FormWizard skips a step is to use a condition_dictionary. Django uses the structure to only include the form for a step when the conditions (set as callables)

# I always specify index values for steps so that all functions can share them
STEP_ONE = u'0'
STEP_TWO = u'1'
STEP_THREE = u'2'


def MyWizard(SessionWizardView):
    # Your form wizard itself; will not be called directly by urls.py, but rather wrapped in a function that provide the condition_dictionary
    _condition_dict = { # a dictionary with key=step, value=callable function that return True to show step and False to not
        STEP_ONE: return_true, # callable function that says to always show this step
        STEP_TWO: check_step_two, # conditional callable for verifying whether to show step two
        STEP_THREE: return_true, # callable function that says to always show this step
    }
    _form_list = [ # a list of forms used per step
        (STEP_ONE,your_forms.StepOneForm),
        (STEP_TWO, your_forms.StepTwoForm),
        (STEP_THREE, your_forms.StepThreeForm),
    ]
    ...


def return_true(wizard): #  callable function called in _condition_dict
    return True # a condition that is always True, for when you always want form seen

def check_step_two(wizard): #  callable function called in _condition_dict
    step_1_info = wizard.get_cleaned_data_for_step(STEP_ONE)
    # do something with info; can retrieve for any prior steps
    if step_1_info == some_condition:
        return True # show step 2
    else: return False # or don't

''' urls.py '''

your_form_wizard = MyWizard.as_view(MyWizard._form_list,condition_dict= MyWizard._condition_dict)

urlpatterns = patterns('',
    ...
    url(r'^form_wizard_url/$', your_form_wizard, name='my-form-wizard',) 
)
0
unicoder On

Thank you, Paulo, for your answer! This is exactly what is needed to easily skip form pages. Building on Paulo's answer, three changes need to be made to skip multiple steps simultaneously:

# I always specify index values for steps so that all functions can share them
STEP_ONE = u'0'
STEP_TWO = u'1'
STEP_THREE = u'2'


def MyWizard(SessionWizardView):
    # Your form wizard itself; will not be called directly by urls.py, but rather wrapped in a function that provide the condition_dictionary

    # **Change1**: functions need to be stated before the dictionary
    def return_true(wizard): #  callable function called in _condition_dict
        return True # a condition that is always True, for when you always want form seen

    # **Change 2:** Only proceed with the logic if the step is valid
    def check_step_two(wizard): #  callable function called in _condition_dict
        step_1_info = wizard.get_cleaned_data_for_step(STEP_ONE)
        # do something with info; can retrieve for any prior steps
        if step_1_info != None:
            if step_1_info == some_condition:
                return True # show step 2
            else: return False # or don't

     # **Change 3**: a condition must be added to skip an additional form
    _condition_dict = { # a dictionary with key=step, value=callable function that return True to show step and False to not
        STEP_ONE: return_true, # callable function that says to always show this step
        STEP_TWO: check_step_two, # conditional callable for verifying whether to show step two
        STEP_THREE: check_step_two, # conditional callable for verifying whether to show step three
        STEP_FOUR: return_true, # callable function that says to always show this step
    }
    _form_list = [ # a list of forms used per step
        (STEP_ONE,your_forms.StepOneForm),
        (STEP_TWO, your_forms.StepTwoForm),
        (STEP_THREE, your_forms.StepThreeForm),
        (STEP_THREE, your_forms.StepFourForm),
    ]
    ...

''' urls.py '''

your_form_wizard = MyWizard.as_view(MyWizard._form_list,condition_dict= MyWizard._condition_dict)

urlpatterns = patterns('',
    ...
    url(r'^form_wizard_url/$', your_form_wizard, name='my-form-wizard',) 
)