如何使用WizardView(Django 1.4)创建动态表单?

时间:2012-11-20 18:43:53

标签: python django django-forms django-formwizard

完整的问题陈述涉及多个步骤,但其核心是这个简单的场景:

假设我有两种形式

from django import forms

class Form1(forms.Form):
    char_field1=forms.CharField(label='field 1')
    char_field2=forms.CharField(label='field 2')
    char_field3=forms.CharField(label='field 3')

class Form2(forms.Form):
    choice_field = forms.ChoiceField()

现在使用django.contrib.formtools.wizard.views.WizardView或其子类我想使用char_field1 - char_field3中用户填充的选项填充choice_field。

我尝试覆盖get_form并在返回Form2时填充choice_field。它确实显示了呈现的表单中的选项,但表单在提交时未验证。

我的直觉觉得它应该是可能的,'怎么样'是我无法弄清楚的。

2 个答案:

答案 0 :(得分:1)

迟到总比没有...我最近自己遇到了这种情况,不得不重写表单(第二步)的init方法,并将一个初始关键字从WizardView传递给表单。从那里我可以有条件地设置表单字段的选择。

我自己的实施 -

views.py

class QuoteWizard(SessionWizardView):
    form_list = [QQFormProductLine, QQProduct, QQProductFluidProperties]
    ...
    def get_form_initial(self, step):
        #pass variables to forms from here
        initial = self.initial_dict.get(step, {})
        if int(step) > 0:
            self.temperature_units, self.measurement_format = self.get_measurement_units()
            initial.update({'measurement_format': self.measurement_format})
        return initial

forms.py

class QQProduct(forms.ModelForm):
    ...
    def __init__(self, *args, **kwargs):
        super(QQProduct, self).__init__(*args, **kwargs)
        units = None 

        if 'initial'in kwargs:
            initial = kwargs.pop('initial')
            if 'measurement_format' in initial:
                units = initial.pop('measurement_format')

        flow_choices = []
        if units == 'imperial':
            flow_units = qq_models.FlowRateUnits()
            flow_units = flow_units.imperial()
        elif units == 'metric':
            flow_units = qq_models.FlowRateUnits()
            flow_units = flow_units.metric()

        for i in flow_units:
            flow_choices.append((i, qq_models.FlowRateUnits.get(i)))
        if len(flow_choices) > 0:
            self.fields['flow_rate_format'].widget.choices = flow_choices

总之,get_form_initial是一个WizardView方法,它将初始关键字传递给步骤的表单。在我的self.get_measurement_units()方法中,我调用self.get_cleaned_data_for_step(' 0'),并根据第一步中的用户输入,在第二步中更改选项字段中显示的选项。形式。

答案 1 :(得分:0)

你可以这样做:

views.py:

from django.contrib.formtools.wizard.views import CookieWizardView

class ChoiceWizardView(CookieWizardView):
    def done(self, form_list, **kwargs):
        pass

    def get_form(self, step=None, data=None, files=None):
        form = super(ChoiceWizardView, self).get_form(step, data, files)
        if 'choice_field' in form.fields:
            form1_cleaned_data = self.get_cleaned_data_for_step('0')
            if form1_cleaned_data:
                form.fields['choice_field'].choices = [item for item in form1_cleaned_data.items()]
        return form

urls.py:

from app.forms import Form1, Form2
from app.views import ChoiceWizardView

urlpatterns = patterns('',
    (r'^my_wizard/$', ChoiceWizardView.as_view([Form1, Form2])),
)

它会起作用。但也许您选择了错误的应用程序架构?