Django 表单向导 - 取决于第一个表单步骤的选择

Posted

技术标签:

【中文标题】Django 表单向导 - 取决于第一个表单步骤的选择【英文标题】:Django form wizard - choices depending on first form step 【发布时间】:2011-06-30 07:25:04 【问题描述】:

我使用 FormWizard 创建了一个两步表单,如下所示:

第一步:询问用户位置 第二步:显示多个搜索结果 取决于用户位置,并将其显示为单选按钮

现在第二种形式取决于第一种形式的输入。几个博客或 *** 帖子涵盖了类似的主题,我按照说明进行操作。 但是,应该在 process_step 期间保存的变量不适用于下一个_init_。

如何将变量位置从 process_step 传达给 _init_?

class reMapStart(forms.Form):
    location = forms.CharField()
    CHOICES = [(x, x) for x in ("cars", "bikes")]
    technology = forms.ChoiceField(choices=CHOICES)

class reMapLocationConfirmation(forms.Form):

   def __init__(self, user, *args, **kwargs):
       super(reMapLocationConfirmation, self).__init__(*args, **kwargs)
       self.fields['locations'] = forms.ChoiceField(widget=Radioselect(), choices=[(x, x)  for x in location])

class reMapData(forms.Form):
   capacity = forms.IntegerField()

class reMapWizard(FormWizard):
   def process_step(self, request, form, step):
       if step == 1:
          self.extra_context['location'] = form.cleaned_data['location']

   def done(self, request, form_list):
       # Send an email or save to the database, or whatever you want with
       # form parameters in form_list
       return HttpResponseRedirect('/contact/thanks/')

非常感谢任何帮助。

谢谢,

PS:帖子已更新为更新的代码。

【问题讨论】:

【参考方案1】:

您可以使用存储对象从任何步骤获取数据:

self.storage.get_step_data('0')

这将返回为该特定步骤保存在存储后端中的数据字典。

在下面的示例中,第一个表单包含一个“活动”下拉选择。然后第二个表单包含一个位置选择小部件,它只显示可用于该活动的位置。

这在您通过向导前进或后退时有效 - 如果您按“prev”,上述答案将不起作用,因为它们仅依赖于前进的向导(即 POST dict 将不包含第 0 步的数据,如果在第 3 步按 prev!)

def get_form(self, step=None, data=None, files=None):

    form = super(EnquiryWizard, self).get_form(step, data, files)
    #print self['forms']['0'].cleaned_data

    step = step or self.steps.current

    if step == '1':
        step_0_data = self.storage.get_step_data('0')
        activity = Activity.objects.get(pk=step_0_data.get('0-activity'))
        locations = Location.objects.filter(activities=activity)
        form.fields['locations'].widget = forms.CheckboxSelectMultiple(choices=[(x.pk,x.name) for x in locations])

    return form

【讨论】:

【参考方案2】:

在Yuji的帮助下(谢谢)解决问题后的工作代码是:

class reMapWizard(FormWizard):

    def render_template(self, request, form, previous_fields, step, context=None):
        if step == 1:
            location = request.POST.get('0-location')
            address, lat, lng, country = getLocation(location)
            form.fields['locations'] = forms.ChoiceField(widget=RadioSelect(), choices = [])
            form.fields['locations'].choices = [(x, x) for x in address]
        return super(reMapWizard, self).render_template(request, form, previous_fields, step, context)

【讨论】:

只是指出,请不要将我的答案重新发布为您的答案。您应该接受有帮助的答案,并通过代码更新来编辑您的问题。【参考方案3】:

我认为您可以直接在您的 __init__ 方法中访问 POST 字典,因为看起来向导通过 get_formPOST 传递到每个表单实例中,但我看不到某些数据原因。

我想出的替代方法是使用render_template 钩子,而不是纠缠太久。

class ContactWizard(FormWizard):
    def done(selef, request, form_list):
        return http.HttpResponse([form.cleaned_data for form in form_list])

    def render_template(self, request, form, previous_fields, step, context=None):
        """
        The class itself is using hidden fields to pass its state, so
        manually grab the location from the hidden fields (step-fieldname)
        """
        if step == 2: 
            locations = Location.objects.filter(location=request.POST.get('1-location'))
            form.fields['locations'].choices = [(x, x) for x in locations]
        return super(ContactWizard, self).render_template(request, form, previous_fields, step, context)

【讨论】:

以上是关于Django 表单向导 - 取决于第一个表单步骤的选择的主要内容,如果未能解决你的问题,请参考以下文章

Django 表单向导 - 每个步骤的自定义表单布局

Django:在表单向导中为步骤动态设置表单集

Django 表单向导独特的 URL 设计

如何显示作为最终 django 表单向导步骤输入的所有数据的预览?

使用 Django 模型表单 + 表单向导 + Crispy - 不进行第二步

django:如何在表单向导中使用 inlineformset?