Search code examples
djangodjango-formsdjango-crispy-forms

Can't Just Append A Delete Button To A Crispy Form


I'm trying to create a fairly simple form that will allow me to update and delete instruments from a database. Everything is working except for HTML rendering, and for that I'm using django-crispy-forms.

The following code works really well if all I want is a Submit button:

forms.py

class InstrumentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(InstrumentForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        # Add a submit button after all of my fields are auto generated in the form.
        self.helper.add_input(Submit('submit', 'Submit'))

    class Meta:
        model = Instrument

views.py

class InstrumentDetailView(generic.UpdateView):
    template_name = 'instrument/details.html'
    form_class = InstrumentForm
    # FIXME Don't hardcode the URL
    success_url = '/inventory/instruments'
    model = Instrument

instrument/details.html

{% extends "shared/base.html" %}
{% load crispy_forms_tags %}

{% block content %}
<h1>Instrument Details</h1>

{% crispy form %}
{% endblock %}

With this configuration, I see all of the fields from my Instrument model rendered perfectly with a Submit button that works.

The problem is that I want to render a "Delete" link next to that Submit button. I've tried the following:

forms.py

class InstrumentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(InstrumentForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        # Add a submit button after all of my fields are auto generated in the form.
        self.helper.add_input(Submit('submit', 'Submit'))
        self.helper.add_input(HTML('<a href=foo>foo</a>'))

    class Meta:
        model = Instrument

But that just renders a button that looks like this:

<input name="" value="" class="" id="-id-" type="">

So it looks like add_input only works for buttons. I then tried the following:

forms.py

class InstrumentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(InstrumentForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()

        button_layout = Layout(
            ButtonHolder(
               Submit('submit', 'Submit'),
               HTML('<a href="foo">foo</a>')
            ),
        )

        self.helper.add_layout(button_layout)

    class Meta:
        model = Instrument

This does actually render my button and link properly, but all of the other fields disappear. I can of course fix this by manually specifying all of the fields in my InstrumentForm class, but I was hoping to avoid that code duplication.

Does anyone know of a way to only append a submit button and arbitrary link to the bottom of an auto-generated form using django-crispy-form? What am I missing?


Solution

  • Here's what I ended up putting in my forms.py file to make this work with Twitter bootstrap:

    class InstrumentForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super(InstrumentForm, self).__init__(*args, **kwargs)
            self.helper = FormHelper()
    
            self.helper.add_input(Submit('submit', 'Submit'))
            self.helper.add_input(Button('delete', 'Delete', onclick='window.location.href="{}"'.format('delete')))
    
        class Meta:
            model = Instrument
    

    Now the Delete button is right next to the Submit button and I don't have to explicitly define any of my other form fields. The Submit button works and I am sent to the following URL when I click on the delete button for item #1:

    http://foo/inventory/instruments/1/delete