【问题标题】:How to create a dynamic form using WizardView (Django 1.4)?如何使用 WizardView (Django 1.4) 创建动态表单?
【发布时间】:2012-11-08 22:03:09
【问题描述】:

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

假设我有两种形式

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。

当要返回 Form2 时,我尝试覆盖 get_form 并填充选择字段。它确实在呈现的表单中显示了选项,但表单在提交时没有验证。

我的直觉告诉我这应该是可能的,“如何”是我无法弄清楚的。

【问题讨论】:

    标签: python django django-forms django-formwizard


    【解决方案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') 并根据第一步中的用户输入,更改第二步表单中选择字段中显示的选项。

    【讨论】:

      【解决方案2】:

      你可以这样做:

      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])),
      )
      

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

      【讨论】:

      • 是的,我已经尝试过了。选择会显示在表单中,但验证失败,说明所选值不是有效选择。
      • 哦。对不起。我没有对此进行测试。我的错。现在它似乎是一个有效的例子。更改条件,当字段填充数据时。
      猜你喜欢
      • 2016-11-11
      • 2012-05-21
      • 2012-11-13
      • 1970-01-01
      • 1970-01-01
      • 2011-04-28
      • 2021-06-03
      • 2019-05-05
      • 1970-01-01
      相关资源
      最近更新 更多