Switching forms in views

Is it possible to switch between forms in a view, based on a field value?

I have this view like this:

class telephone_view(UpdateView):
    template_name = 'account/telephone.html'
    form_class = TelephoneForm
    success_url = '/accounts/telephone/'

    def get_object(self, queryset=None):
        return Profile.get_or_create_for_user(self.request.user)

    def form_valid(self, form):
        messages.success(self.request, _('Your telephone setting was updated'))
        return super(telephone_view, self).form_valid(form)

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(telephone_view, self).dispatch(*args, **kwargs)

I would like to use a different form_class according to the value of a field not used on the form, essentially because I want different form fields to be available, so, something like:

if self.request.user.profile.status == 'managed':
    form_class = TelephoneFormExtended
else:
    form_class = TelephoneFormLight

Although I can get the if to evaluate correctly within the defined functions in the view class telephone_view after a number of failed attempts I cannot work out how to change the form that is produced.

Am I barking up the wrong tree, is there some other technique to achieve this?

Thanks

Ok, I think I found the answer! I went over my research again, and did some more searching, and I found: https://ccbv.co.uk/ (thanks to https://simpleisbetterthancomplex.com/series/2017/10/09/a-complete-beginners-guide-to-django-part-6.html).

Then I discovered that there’s a function in UpdateView get_form_class. So I updated my telephone_view class:

# views.py
class telephone_view(UpdateView):
    template_name = 'account/telephone.html'
    #no need to define "form_class" here
    #form_class = TelephoneForm
    success_url = '/accounts/telephone/'

    def get_form_class(self):
        if self.request.user.profile.status == 'managed':
            messages.success(self.request, _('you got the managed form'))
            return TelephoneFormExtended
        else:
            messages.success(self.request, _('you got the other form'))
            return TelephoneFormLight

    def get_object(self, queryset=None):
        return Profile.get_or_create_for_user(self.request.user)

    def form_valid(self, form):
        messages.success(self.request, _('Your telephone setting was updated'))
        return super(telephone_view, self).form_valid(form)

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(telephone_view, self).dispatch(*args, **kwargs)

Which all magickly works as I expected. All seems too simple, am I missing something!?

Nope, you’re not missing anything. That’s the beauty of building on CBVs, so much of the boilerplate code is already taken care of and there’s usually a hook for anything you may need to do that’s not by default.

1 Like