Have multiple submit buttons for the same Django form

Django form with two submit buttons
Image: Django form with two submit buttons (License: CC-BY-SA Marcelo Canina)

Behave differently depending on which button the user clicks

Published:

Overview

Guide to add multiple submit buttons to a form and attach a different behaviour to each of them using Django's Class Based Views.

Explanation

For this example we will use a typical Django form template looking like:

<form method="post">{% csrf_token %}
{{ form }}
<input class="btn btn-primary" type="submit" value="Save" />
</form>

Using this CBV:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import CreateView

from models import MyModel

class MyView(LoginRequiredMixin, CreateView):
    """
    A view that displays a form for creating an object, redisplaying the form with validation errors (if there are any) and saving the object.
    """
    model = MyModel

So we will add another submit button displaying the text: Save and add text in addition to the already showed Save button that redirects to another page.

Process

1. Adding the button

We will focus our attention in the form's input element.

Using its name attribute to differentiate it from other input buttons.

In our template, we add an input element with name="add_text":

<input class="btn btn-primary" type="submit" value="Save" />
<input class="btn btn-primary" type="submit" name="add_text" value="Save and add text" />

2. Processing the form

The key to process the form and know which button the user used, is to use the get_success_url() function to adjust the behaviour we want.

Any CBV that inherits from django.views.generic.edit.FormMixin will have it like CreateView, UpdateView and DeleteView.

Then the submit button used will be in the self.request.POST variable which will be a QueryDict object containing the above button name.

So it will contain something like:

QueryDict: {'csrfmiddlewaretoken':
['crvObJ2k8jRClFX9vr6ZmNiDCtaMAzM6a148BxobrfoHaJGhFxs3pQDxS4F7XXX'],
'title': ['Example Foo Bar'], 'add_text': ['Save and add text']}

And we can check if the submit name value is present in the above dictionary.

Putting it all together in the view:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from django.views.generic import CreateView

from models import MyModel

class MyView(LoginRequiredMixin, CreateView):
    """
    A view that displays a form for creating an object, redisplaying the form with validation errors (if there are any) and saving the object.
    """
    model = MyModel

    def get_success_url(self):
	    """Detect the submit button used and act accordingly"""
        if 'add_text' in self.request.POST:
            url = reverse_lazy('add-text')
        else:
            url = reverse_lazy('model-detail', kwargs={
	             //...
            })
        return url

References

Uruguay
Marcelo Canina
I'm Marcelo Canina, a developer from Uruguay. I build websites and web-based applications from the ground up and share what I learn here.
comments powered by Disqus


How to have more than one submit button with different behaviour attached to the same form in Django.

Clutter-free software concepts.
Translations English Espa簽ol