You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django FormWizard中Formset ChoiceField不更新及报错排查

Hey there, let's break down and fix the issues you're having with your Django FormWizard!

First, let's understand why your original approaches weren't working:

  • The get_form_initial method is only meant to return a dictionary of initial values, not a formset object. That's why you got the 'TestForm' object has no attribute 'get' error.
  • When you switched to get_form, modifying the global form_class.extra and updating fields after instantiating the formset caused mismatches with the management form data—hence the ManagementForm data is missing or has been tampered with error. Also, updating fields post-instantiation doesn't play nicely with form validation and data handling.

Here's the corrected approach

We'll dynamically create a temporary formset class (to avoid messing with global settings) and update the ChoiceField options directly in the form's __init__ method. This ensures everything stays in sync with the wizard's data flow.

Updated views.py code

class FormWizardView(LoginRequiredMixin, SessionWizardView):
    template_name = 'test/test.html'
    
    def get_form(self, step=None, data=None, files=None):
        step = step or self.steps.current
        if step == 'formset_step':
            # Fetch cleaned data from previous steps
            slider_data = self.get_cleaned_data_for_step('slider_step')
            text_input_data = self.get_cleaned_data_for_step('text_input_step')
            
            if slider_data and text_input_data:
                # 1. Get the base form class from your pre-defined formset
                base_form = self.form_list[step].form
                
                # 2. Create a dynamic form class to update the ChoiceField
                class DynamicForm(base_form):
                    def __init__(self, *args, **kwargs):
                        super().__init__(*args, **kwargs)
                        # Convert your text input data to valid choices format
                        # Adjust this if your text_input_data isn't a key-value dict
                        self.fields['text_input'].choices = [
                            (key, value) for key, value in text_input_data.items()
                        ]
                
                # 3. Create a temporary formset with the correct 'extra' count
                from django.forms import formset_factory
                DynamicFormSet = formset_factory(
                    DynamicForm,
                    extra=slider_data['number_slider']
                )
                
                # 4. Return the formset with proper prefix and data/files
                return DynamicFormSet(
                    data=data,
                    files=files,
                    prefix=self.get_form_prefix(step)
                )
        
        # Fall back to default behavior for other steps
        return super().get_form(step, data, files)
    
    def done(self, form_list, **kwargs):
        # Handle your form submission logic here
        # Example: save the formset data
        # for form in form_list:
        #     if hasattr(form, 'forms'):
        #         form.save()
        return HttpResponse("Form submission successful!")

Key fixes explained

  1. No global modifications: We use formset_factory to create a temporary formset class instead of altering the global one. This prevents side effects for other users or subsequent requests.
  2. ChoiceField updates in __init__: By defining a dynamic form class, we ensure every form in the formset gets the updated choices when it's instantiated—this is the correct place to modify fields dynamically.
  3. Proper management form handling: Passing the correct prefix (from self.get_form_prefix(step)) ensures the management form fields match what the wizard expects, fixing the tampering error.
  4. Data/files passed correctly: We forward the data and files parameters to the formset, so existing input (if any) is preserved and validated properly.

Your template is fine!

You don't need to change anything in your template—keeping {{ wizard.management_form }} in place is exactly what we need for the formset to work correctly.

Quick check

Make sure the cleaned data from text_input_step is a dictionary (key-value pairs). If your text input collects data in a different format, adjust the choices list generation to match Django's required (value, label) tuple format.

内容的提问来源于stack exchange,提问作者Motta23

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:02:21