Django 表单向导 - 根据第一个表单步骤进行选择

发布于 2024-10-18 12:46:51 字数 1294 浏览 4 评论 0原文

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

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

现在第二个表单取决于第一个表单的输入。几个博客或 stackoverflow 帖子涵盖了类似的主题,我按照说明进行操作。 但是,应该在 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/')

非常感谢任何帮助。

谢谢, H

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

I have created a 2 step form with the FormWizard as follows:

  • 1st step: asking user for location
  • 2nd step: show several search results
    depending on the user location, and display it as radioButtons

Now the second form depends on the input of the first form. Several blogs or stackoverflow posts cover similar topics, and I followed the instructions.
However, the variable which is supposed to be saved during the process_step is not available for the next _init_.

How do I communicate the variable location from the process_step to _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/')

Any help is absolutely appreciated.

Thanks,
H

PS: posting was updated with newer code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

生生漫 2024-10-25 12:46:51

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

我没有花太多时间思考这个问题,而是使用 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)

I figured you could just access the POST dictionary directly in your __init__ method because it looks like the wizard passes POST into each form instance via get_form, but I don't see the data for some reason.

Instead of dwelling on that too long the alternative I've come up with is using the render_template hook.

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)
浮世清欢 2024-10-25 12:46:51

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

self.storage.get_step_data('0')

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

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

当您在向导中前进或后退时,这会起作用 - 如果您按“上一步”,上述答案将不起作用,因为它们仅依赖于向导前进(即,如果您按上一步,则 POST 字典将不包含步骤 0 的数据)在第 3 步!)

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

You can get the data from any step by using the storage object:

self.storage.get_step_data('0')

this will return the data dict saved in the storage backend for that particular step.

In my example below, the first form contains an 'Activity' drop down select. Then the second form contains a location select widget which only shows locations that are available for that activity.

This works when you go forward or backward through the wizard - the above answers don't work if you press 'prev' as they rely on the wizard going forward only (i.e. the POST dict won't contain step 0's data if you press prev on step 3!)

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
方圜几里 2024-10-25 12:46:51

在 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)

The working code, after solving the problem with Yuji's help (Thank you) is:

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文