I've been using django-crispy-forms with Bootstrap 4 on a little Django project which has saved me a ton of manual Bootstrap formatting effort. One tiny issue I came across was crispy forms has nice Submit
and Button
objects to add buttons to forms. However I wanted a Cancel and Delete button on my UpdateView
but using the Button
object will cause the form to POST which isn't what I want.
The simplest solution seems to be directly using crispy's HTML
object, described aptly in the docs:
HTML: A very powerful layout object. Use it to render pure html code. In fact it behaves as a Django template and it has access to the whole context of the page where the form is being rendered:
HTML("{% if success %} <p>Operation was successful</p> {% endif %}")
Access to the whole template context? Yes please! Specifically for the delete button we need to pass a parameter, the object.id
of the current object, to the delete route. Additionally the delete button is wrapped in an {% if object %}
tag to only display if there is an existing form to delete. For example if you reuse the form template for your CreateView
then accessing object
will throw an error, it doesn't exist yet!
myapp/forms.py
class TicketForm(forms.ModelForm):
helper = FormHelper()
helper.layout = Layout(
Fieldset(
# ... all your layout stuff
),
FormActions(
Submit('submit', 'Save', css_class="btn btn-outline-success"),
HTML("""<a href="{% url "ticket-list" %}" class="btn btn-secondary">Cancel</a>"""),
HTML("""{% if object %}
<a href="{% url "ticket-delete" object.id %}"
class="btn btn-outline-danger pull-right">
Delete <i class="fa fa-trash-o" aria-hidden="true"></i></button></a>
{% endif %}"""),
)
)
myapp/urls.py
urlpatterns = [
url(r'^ticket/$', views.TicketListView.as_view(), name='ticket-list'),
url(r'^ticket/new/$', views.TicketCreateView.as_view(), name='ticket-new'),
url(r'^ticket/(?P<pk>[0-9]+)/$', views.TicketUpdateView.as_view(), name='ticket-edit'),
url(r'^ticket/(?P<pk>[0-9]+)/delete/$', views.TicketDeleteView.as_view(), name='ticket-delete'),
]
myapp/views.py
class TicketCreateView(CreateView):
model = Ticket
form_class = TicketForm
# ...
class TicketUpdateView(UpdateView):
model = Ticket
form_class = TicketForm
# ...
class TicketDeleteView(DeleteView):
model = Ticket
form_class = TicketForm
# ...
templates/ticket/ticket_form.html
{% extends 'page_setup.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="row">
<div class="col">
{% crispy form %}
</div>
</div>
{% endblock %}