djangodjango-formwizard

I'm trying to override a django formtools wizard form widget, but it is just using the standard widget


I have the following form

class ProviderSignUp1(forms.ModelForm):
    class Meta:
        model = models.Provider
        fields = [ 
            'childcare_type_informal',
            'childcare_type_accredited',
        ]
        wigdets = {
            'childcare_type_informal': PatchRadioSelect(
                attrs={
                    'class':'form-control'
                }
            ),
            'childcare_type_accredited': PatchRadioSelect(
                attrs={
                    'class':'form-control'
                }
            )
        }

    def clean(self):
        cleaned_data = self.cleaned_data
        if cleaned_data['childcare_type_informal'] == True and cleaned_data['childcare_type_accredited'] == True:
            raise ValidationError("You must select only one type of childcare")
        if cleaned_data['childcare_type_informal'] == False and cleaned_data['childcare_type_accredited'] == False:
            raise ValidationError("You must select at least one type of childcare")

        return super().clean()

The widget is defined as

from django.forms.widgets import RadioSelect

class PatchRadioSelect(RadioSelect):
    template_name = 'userprofiles/form_widgets/radio.html'
    option_template_name = 'userprofiles/form_widgets/radio_option.html'

And my wizard is:

PROVIDER_SIGNUP_TEMPLATES = {
    'page0': 'userprofiles/provider_signup_wizard/page0.html',
    'page1': 'userprofiles/provider_signup_wizard/page1.html',
    'page2': 'userprofiles/provider_signup_wizard/page2.html',
    'page3': 'userprofiles/provider_signup_wizard/page3.html',
    'page4': 'userprofiles/provider_signup_wizard/page4.html',
    'page5': 'userprofiles/provider_signup_wizard/page5.html',
    'page6': 'userprofiles/provider_signup_wizard/page6.html',
    'page7': 'userprofiles/provider_signup_wizard/page7.html',
    'page8a': 'userprofiles/provider_signup_wizard/page8.html',
    'page8b': 'userprofiles/provider_signup_wizard/page8.html',
    'page9': 'userprofiles/provider_signup_wizard/page9.html',
    'page10': 'userprofiles/provider_signup_wizard/page10.html',
}

PROVIDER_SIGNUP_FORMS = [
    ("page0", forms.ProviderSignUp0),
    ("page1", forms.ProviderSignUp1),
    ("page2", forms.ProviderSignUp2),
    ("page3", forms.ProviderSignUp3),
    ("page4", forms.ProviderSignUp4),
    ("page5", forms.ProviderSignUp5),
    ("page6", forms.ProviderSignUp6),
    ("page7", forms.ProviderSignUp7),
    ("page8a", forms.ProviderSignUp8a),
    ("page8b", forms.ProviderSignUp8b),
    ("page9", forms.ProviderSignUp9),
    ("page10", forms.ProviderSignUp10),
]

def accredited_only_condition(wizard):
    cleaned_data = wizard.get_cleaned_data_for_step('page1') or {}
    return cleaned_data.get('childcare_type_accredited', True)

def informal_only_condition(wizard):
    cleaned_data = wizard.get_cleaned_data_for_step('page1') or {}
    return cleaned_data.get('childcare_type_informal', True)

class ProviderSignUpWizard(SessionWizardView):
    form_list = PROVIDER_SIGNUP_FORMS
    condition_dict = {
        'page2': accredited_only_condition,
        'page8a': accredited_only_condition,
        'page8b': informal_only_condition,
        'page9': informal_only_condition,
    }

    def get_form_instance(self, step):
        if step == 'page4':
            return self.instance_dict.get(step, self.request.user)    
        return self.instance_dict.get(step, self.request.user.provider)

    def get_template_names(self):
        return [PROVIDER_SIGNUP_TEMPLATES[self.steps.current]]

    def done(self, form_list, **kwargs):
        provider_instance = models.Provider.objects.get(id=self.request.user.provider.id)
        user_instance = models.User.objects.get(id=self.request.user.id)
        for form in form_list:
            provider_instance = construct_instance(form, provider_instance, form._meta.fields, form._meta.exclude)
            user_instance = construct_instance(form, user_instance, form._meta.fields, form._meta.exclude)
        
        provider_instance.save()
        user_instance.save()

        return redirect(self.request.user.get_provider_profile_url())


    def post(self, *args, **kwargs):
        form = self.get_form(data=self.request.POST, files=self.request.FILES)                                                      
        

        if form.is_valid():
            form.save()
            if 'services' in form.cleaned_data:
                models.Provider.objects.get(id=self.request.user.provider.id).services.set(form.cleaned_data['services'])
            if 'features' in form.cleaned_data:
                models.Provider.objects.get(id=self.request.user.provider.id).features.set(form.cleaned_data['features'])
            if 'informal_phrases' in form.cleaned_data:
                models.Provider.objects.get(id=self.request.user.provider.id).informal_phrases.set(form.cleaned_data['informal_phrases'])
        return super().post(*args, **kwargs) 

My widget is being ignored and the standard widget is being used. Please note, I seem unable to change any of the widgets from the standard and can only add attributes to the existing widget. What am I doing wrong?


Solution

  • Just in case anyone else comes across the same issue, I found if I define __init__ within the first form in the wizard, I can then override the widgets within __init__ in whichever form I need to use it. But it doesn't work if I don't specify __init__ in the first form.

    I think this more a workaround than solution.