Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: Multiple forms possible when using FormView?

Tags:

python

django

I've recently learned Django forms by subclassing FormView, where the desired form is assigned to the FormView.form_class attribute. When the form validates, the form_valid() method is invoked (for that one form). For example:

from accounts.forms import SignUpForm, UpdateAccountForm, UpdateBillingForm

class SignUpView(FormView):
    form_class = SignUpForm

    def form_valid(self, form):
    # code when form validates...

However, I now have a situation where I need three unique forms on one page (with only one form visible to the user at a time). So, I'd like to handle them all in the same View.

Are multi-form pages possible using FormView? I'm not sure how to handle it, both in terms of passing multiple forms to the View (e.g. the other UpdateAccountForm and UpdateBillingForm), as well as distinguishing which one was submitted/validated? What would be the best way?

like image 525
pete Avatar asked Jan 21 '14 19:01

pete


People also ask

How many types of Django forms are there?

Django form fields define two types of functionality, a form field's HTML markup and its server-side validation facilities.

How do you receive data from a Django form with a post request?

Using Form in a View In Django, the request object passed as parameter to your view has an attribute called "method" where the type of the request is set, and all data passed via POST can be accessed via the request. POST dictionary. The view will display the result of the login form posted through the loggedin.


1 Answers

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 (?)

like image 56
pete Avatar answered Oct 15 '22 13:10

pete