【问题标题】:skipping step x to step y and validate step x data跳过步骤 x 到步骤 y 并验证步骤 x 数据
【发布时间】:2016-01-20 16:09:10
【问题描述】:

我实际上在 django 向导表单上遇到了一个大问题。

我有 3 个步骤。第二步可以包含或不包含数据。最后一步是文件上传步骤。

在 WizardForm 类中,我重写了 get_context_data 方法并将其包含在其中:

if self.steps.current == 'against_indication':
        questions = None
        try:
            # get the machine
            machine_id = self.kwargs['pk']
            machine = Machine.objects.get(pk=int(machine_id))
            # check if there is against indications
            if machine.type_question is False:
                questions = YhappsQuestion.objects.filter(type_modalite=machine.type)
            else:
                questions = CustomQuestion.objects.filter(machine=machine)
        except Machine.DoesNotExist:
                pass
        if len(questions) == 0:
            # we modify the form wizard to skip against indication step
            self.render_next_step(form, **kwargs)
            #self.render_goto_step(step='against_indication', goto_step='prescription', **kwargs)

如您所见,如果没有问题,我跳过第二步(反对指示)进入下一步(处方)。

问题出现在这里。渲染最后一步时,向导表单中没有足够的数据。在 ddt 的请求中有它: with skip step。 因此,如果我上传文件,它将填充反对指示数据而不是处方数据,并重新渲染我最后一步...

我尝试在不跳过第二步的情况下完成所有这些操作,看看 ddt 的请求如何: without skip step.

当我跳过步骤时,有人有一个解决方案允许拥有正确的数据,请?

感谢您的进一步回答

【问题讨论】:

    标签: django django-formwizard


    【解决方案1】:

    我不认为get_context_data 是这样做的正确方法; FormWizard 是一个非常具体的类,它限制了您可以执行不同功能的位置。

    指定FormWizard 何时跳过步骤的典型方法是使用condition_dictionary。当条件(设置为可调用对象)返回True 时,Django 使用该结构仅包含步骤的表单。如果不是,则该步骤的表单不会强制调用form.is_valid(),从而绕过该步骤的验证。这也确保为每个步骤创建表单的所有隐藏管理信息。

    这是一个如何工作的示例:

    # 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 YourFormWizard(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 = YourFormWizard.as_view(YourFormWizard._form_list,condition_dict= YourFormWizard._condition_dict)
    
    urlpatterns = patterns('',
        ...
        url(r'^form_wizard_url/$', your_form_wizard, name='my-form-wizard',) 
    )
    

    【讨论】:

    • 感谢@IanPrice!这个使用 condition_dict 的例子确实比官方的 django 例子更不稳定。它拯救了我的一天:)
    • 很高兴听到!是的,文档对于 FW 来说真的不是很好。
    • 如果我能提供帮助,请将其标记为答案并点赞:)
    • @IanPrice 感谢您的出色回答。我试图在另一个答案中改进它。如果有帮助,请告诉我。
    【解决方案2】:

    根据 Ian Price 的出色回答,我尝试进行一些改进,因为我注意到结构会随着时间的推移有所帮助,尤其是当您尝试更改步骤顺序时:

    • 我使用数据类来集中有关步骤向导的数据,然后为 url 生成所需的数据。
    • 我使用 lambdas 来返回 True 并且给 callable 是可选的
    • 我将 STEP_X 提取到一个 const.py 文件中以便重复使用
    • 我尽量在类视图本身而不是函数中收集数据

    这里是代码(Python 3.7+):

    const.py

    STEP_0 = '0'
    STEP_1 = '1'
    STEP_2 = '2'
    

    views.py

    from dataclasses import dataclass
    from typing import Optional, Callable, Sequence
    
    
    @dataclass
    class WizardStepData:
        step: str
        form_class: any
        trigger_condition: Optional[Callable] = None
    
        def __init__(self, step, form_class, trigger_condition=None):
            """ if trigger_condition is not provided, we return a Callable that returns True """
            self.step = step
            self.form_class = form_class
            self.trigger_condition = trigger_condition if trigger_condition else lambda _: True
    
    
    def YourFormWizard(SessionWizardView):
        @staticmethod
        def check_step_one(wizard) -> bool:
            pass  # ...
    
        @classmethod
        def get_wizard_data_list(cls) -> Sequence:
            return [
                WizardStepData(step=STEP_0,
                               form_class=StepZeroForm),
                WizardStepData(step=STEP_1,
                               form_class=StepOneForm,
                               trigger_condition=cls.check_step_one),
                WizardStepData(step=STEP_2,
                               form_class=StepTwoForm),
            ]
    
        @classmethod
        def _condition_dict(cls) -> dict:
            return {data.step: data.trigger_condition for data in cls.get_wizard_data_list()}
    
        @classmethod
        def _form_list(cls) -> list:
            return [(data.step, data.form_class) for data in cls.get_wizard_data_list()]
    

    urls.py

    # ...
    your_form_wizard = YourFormWizard.as_view(form_list=YourFormWizard._form_list(),
                                              condition_dict=YourFormWizard._condition_dict())
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多