django-crispy-forms and the 'cancel' button
I use crispy-forms to render my Django forms. With crispy-forms there is almost no need to write any HTML. The template for form views can look like this:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% crispy form %}
{% endblock content %}
By itself, this does not render a submit button. It has to be added to the form definition (cf. the crispy-forms documentation like this:
from potatoes.models import Potato
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from django import forms
class PotatoForm(forms.ModelForm):
"""ModelForm for the Potato model."""
class Meta: # noqa
model = Potato
fields = (
'weight',
'variety',
)
def __init__(self, *args, **kwargs):
"""Initiate form with Crispy Form's FormHelper."""
super(PotatoForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
# Add 'Submit' button
self.helper.add_input(Submit('submit', 'Submit'))
A view that uses this form is my example project’s PotatoCreateView
:
class PotatoCreateView(CreateView):
"""Create view for the Potato model."""
model = Potato
form_class = PotatoForm
template_name = 'potatoes/potato_form.html'
A submit button is nice, but I also want a cancel button. I add it to the crispy-forms helper
, but that just shows a button that does the same as the submit button.
# Add 'Submit' button
self.helper.add_input(Submit('submit', 'Submit'))
self.helper.add_input(Submit('cancel', 'Cancel', css_class='btn-danger',)
I need to overwrite the view’s post
method to do what I want, when the cancel button is clicked. For this, I use a model mixin, because why not.
class FormActionMixin(object):
def post(self, request, *args, **kwargs):
"""Add 'Cancel' button redirect."""
if "cancel" in request.POST:
url = reverse('index') # or e.g. reverse(self.get_success_url())
return HttpResponseRedirect(url)
else:
return super(FormActionMixin, self).post(request, *args, **kwargs)
class PotatoCreateView(FormActionMixin, CreateView):
"""Create view for the Potato model."""
...
When the cancel button is clicked, the resulting POST
request includes the name
attribute of the button. Overwriting the post
method for this case let’s me redirect the user to whatever page I want.
(note to self: research the Django way of redirecting to the previous page.)
Now I have a submit and a cancel button. But on my CreateView it complains about required form fields.
This has to do with HTML, and I found the solution on Coderwall: the HTML attribute formnovalidate
.
self.helper.add_input(Submit('submit', 'Submit'))
self.helper.add_input(Submit(
'cancel',
'Cancel',
css_class='btn-danger',
formnovalidate='formnovalidate',
)
)
That’s it.
(note to self: I need a test for this.)
Categories: #Tech Tags: #Django #Form #Crispy-Forms