[Django]-Django: Multiple forms possible when using FormView?

27šŸ‘

Well, for what itā€™s worth hereā€™s what ultimately worked for me, using a generic View.

1) I added a hidden input field (named ā€˜actionā€™) to each individual form on the page. For example, this is the form for updating userā€™s info, which is pulling in UserForm:

<form action='/account/' method='post'>{% csrf_token %}
   <input type='hidden' name='action' value='edit_user'> 
   {{ user_form.as_p }}
   <input type='submit' value='Update'>
</form>

2) In my View logic, I can distinguish the forms by applying a prefix (per other SO posts and Django docs). Then, depending on the incoming ā€˜actionā€™, I only bind the applicable form to the POST request (so validations arenā€™t applied across all of them). In my case, I had two forms defined in forms.py, UserForm and BillingForm:

from django.views.generic.edit import View
from django.shortcuts import render
from django.http import HttpResponse

from accounts.forms import UserForm, BillingForm

class AccountView(View):

    def get(self, request):
        # code for GET request...

    def post(self, request):
        #instantiate all unique forms (using prefix) as unbound
        user_form    = UserForm(prefix='user_form')
        billing_form = BillingForm(prefix='billing_form')

        # determine which form is submitting (based on hidden input called 'action')
        action = self.request.POST['action']

        # bind to POST and process the correct form
        if (action == 'edit_user'):
            user_form = UserForm(request.POST, prefix='user_form')
            if user_form.is_valid():
                # user form validated, code away..

        elif (action == 'edit_billing'):
            billing_form = BillingForm(request.POST, prefix='billing_form')
            if billing_form.is_valid():
                # billing form validated, code away..

        # prep context
        context = {
            'user_form':    user_form,
            'billing_form': billing_form,
        }
        return render(request, 'accounts/account.html', context) 

Seems to work well, hopefully this is the right approach (?)

šŸ‘¤pete

1šŸ‘

You can write a plain python class mimicking the Form API (at least the useful parts) and wrapping your three forms. Detecting which form has been submitted is just a matter of adding a hidden input with the formā€™s identifier in each form (hint : use prefixes for your forms and use that same prefix as identifier).

The other solution is to use a simple function-based view instead, but even there Iā€™d still use the same ā€œform wrapperā€ pattern as far as Iā€™m concerned.

Leave a comment