跳过步骤 x 到步骤 y 并验证步骤 x 数据
skipping step x to step y and validate step x data
我在 django 向导表单上遇到了一个大问题。
我有 3 个步骤。第二步可以包含数据,也可以不包含数据。最后一步是文件上传步骤。
在 WizardForm class 中,我覆盖了 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)
如你所见,如果没有问题,我跳过第二步(against_indication)进入下一步(处方)。
问题出现在这里。呈现最后一步时,向导表单中没有足够的数据。在 ddt 的请求中有它:
with skip step。
因此,如果我上传文件,它将填充 against_indication 数据而不是处方数据,并在最后一步重新渲染我...
我尝试在不跳过第二步的情况下完成所有这些操作,看看 ddt 的要求如何:
without skip step.
有人有解决方案可以在我跳过步骤时获得正确的数据,请问?
感谢您的进一步回答
我认为 get_context_data
不是执行此操作的正确方法; FormWizard 是一个非常具体的 class,它限制了您可以执行不同功能的位置。
指定 FormWizard
何时跳过步骤的典型方法是使用 condition_dictionary
。 Django 使用该结构仅在条件(设置为可调用项)return True
时包含步骤的表单。如果不是,则该步骤的表单不会强制调用 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',)
)
根据 Ian Price 的出色回答,我尝试进行一些改进,因为我注意到随着时间的推移,结构会有所帮助,尤其是当您尝试更改步骤顺序时:
- 我使用数据class 来集中有关步骤向导的数据,然后为 url 生成所需的数据。
- 我使用 lambda 来返回 True 并且提供 callable 是可选的
- 我在 const.py 个文件中提取 STEP_X 为 re-usable
- 我尽可能地在 class 视图中收集数据,而不是在函数中收集数据
这是代码(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())
我在 django 向导表单上遇到了一个大问题。
我有 3 个步骤。第二步可以包含数据,也可以不包含数据。最后一步是文件上传步骤。
在 WizardForm class 中,我覆盖了 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)
如你所见,如果没有问题,我跳过第二步(against_indication)进入下一步(处方)。
问题出现在这里。呈现最后一步时,向导表单中没有足够的数据。在 ddt 的请求中有它: with skip step。 因此,如果我上传文件,它将填充 against_indication 数据而不是处方数据,并在最后一步重新渲染我...
我尝试在不跳过第二步的情况下完成所有这些操作,看看 ddt 的要求如何: without skip step.
有人有解决方案可以在我跳过步骤时获得正确的数据,请问?
感谢您的进一步回答
我认为 get_context_data
不是执行此操作的正确方法; FormWizard 是一个非常具体的 class,它限制了您可以执行不同功能的位置。
指定 FormWizard
何时跳过步骤的典型方法是使用 condition_dictionary
。 Django 使用该结构仅在条件(设置为可调用项)return True
时包含步骤的表单。如果不是,则该步骤的表单不会强制调用 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',)
)
根据 Ian Price 的出色回答,我尝试进行一些改进,因为我注意到随着时间的推移,结构会有所帮助,尤其是当您尝试更改步骤顺序时:
- 我使用数据class 来集中有关步骤向导的数据,然后为 url 生成所需的数据。
- 我使用 lambda 来返回 True 并且提供 callable 是可选的
- 我在 const.py 个文件中提取 STEP_X 为 re-usable
- 我尽可能地在 class 视图中收集数据,而不是在函数中收集数据
这是代码(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())