Same view for separate actions

Perhaps you find splitting the views to handle forms to be unnecessary, or you find handling logically related forms in a common view to be more elegant. Either way, we can work around the limitations of generic class-based views to handle more than one form.

While using the same view class for multiple forms, the challenge is to identify which form issued the POST action. Here, we take advantage of the fact that the name and value of the Submit button is also submitted. If the Submit button is named uniquely across forms, then the form can be identified while processing.

Here, we define a SubscribeForm using crispy forms so that we can name the Submit button as well:

class SubscribeForm(forms.Form): 
    email = forms.EmailField() 
 
    def __init__(self, *args, **kwargs): 
        super().__init__(*args, **kwargs) 
        self.helper = FormHelper(self) 
        self.helper.layout.append(Submit('subscribe_butn', 'Subscribe')) 

The UnSubscribeForm class is defined in exactly the same way (and hence is omitted), except that its Submit button is named unsubscribe_butn.

Since FormView is designed for a single form, we will use a simpler class-based view, say TemplateView, as the base for our view. Let's take a look at the view definition and the get method:

from .forms import SubscribeForm, UnSubscribeForm 
 
class NewsletterView(generic.TemplateView): 
    subcribe_form_class = SubscribeForm 
    unsubcribe_form_class = UnSubscribeForm 
    template_name = "newsletter.html" 
 
    def get(self, request, *args, **kwargs): 
        kwargs.setdefault("subscribe_form", self.subcribe_form_class()) 
        kwargs.setdefault("unsubscribe_form", self.unsubcribe_form_class()) 
        return super().get(request, *args, **kwargs) 

The two forms are inserted as keyword arguments, and thereby enter the template context. We create unbound instances of either form only if they don't already exist, with the help of the setdefault dictionary method. We will soon see why.

Next, we will take a look at the POST method, which handles submissions from either form:

    def post(self, request, *args, **kwargs): 
        form_args = { 
            'data': self.request.POST, 
            'files': self.request.FILES, 
        } 
        if "subscribe_butn" in request.POST: 
            form = self.subcribe_form_class(**form_args) 
            if not form.is_valid(): 
                return self.get(request, 
                                   subscribe_form=form) 
            return redirect("success_form1") 
        elif "unsubscribe_butn" in request.POST: 
            form = self.unsubcribe_form_class(**form_args) 
            if not form.is_valid(): 
                return self.get(request, 
                                   unsubscribe_form=form) 
            return redirect("success_form2") 
        return super().get(request) 

First, the form keyword arguments, such as data and files, are populated in a form_args dictionary. Next, the presence of the first form's Subscribe button is checked in request.POST. If the button's name is found, then the first form is instantiated.

If the form fails validation, then the response created by the GET method with the first form's instance is returned. In the same way, we look for the second form's Unsubscribe button to check whether the second form was submitted.

Instances of the same form in the same view can be implemented in the same way with form prefixes. You can instantiate a form with a prefix argument such as SubscribeForm(prefix="offers"). Such an instance will prefix all its form fields with the given argument, effectively working like a form namespace. In general, you can use prefixes to embed multiple forms in the same page.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.251.169