Search code examples
djangobootstrap-table

Bootstrap Table not sending selected checkbox values in POST request in Django app


I am using Bootstrap Table (https://bootstrap-table.com/) to display a product list in a Django app. I would like the user to select some products and click the button to submit. Using Bootstrap Table seems to prevent the checked checkboxes being sent in the POST request.

views.py

class ProductProcessView(View):
    def post(self, request):
        products = request.POST.getlist('product_checkboxes')
        # process the chosen products
        return redirect('product-list')

html template

<form method="post">
    {% csrf_token %}
    <table class="table-striped"
           data-toggle="table"
    >
        <thead>
        <tr>
            <th data-field="product_id" data-checkbox="true"></th>
            <th data-field="product">Product</th>
        </tr>
        </thead>
        {% for product in product_list %}
            <tr>
                <td><input type="checkbox" name="product_checkboxes" value="{{ product.id }}"></td>
                <td>{{ product.short_name }}</td>
            </tr>
        {% endfor %}
    </table>
    <button onclick="location.href='{% url 'process-products' %}'">Select Products</button>
</form>

If I remove the line data-toggle="table" this correctly sends the selected product IDs in the POST request, but with that line included it does not send any IDs at all. Bootstrap Table requires the data-toggle="table" attribute to initialise the table so without it there is no formatting.

This is the request.body with data-toggle="table" included:
<QueryDict: {'csrfmiddlewaretoken': ['fOma6gtvG2ETw1hrVYMdIuSUWuE1RA2jpX2Tae7ntipMPGX4yKNYEGgkHD0Jcuco'], 'btSelectItem': ['on', 'on']}>

This is without it:
<QueryDict: {'csrfmiddlewaretoken': ['Si6UyiTZ4yAJNYKKQ9FtA8dk0gNPGTPp2rMDCgxRROlC6DqntVGewkBKLp9x1NZu'], 'product_checkboxes': ['43004', '43006']}>

I would be very grateful for any ideas about how I can use the Bootstrap Table framework with it's formatting and widgets, but still be able to use checkboxes to collect the product data.


Solution

  • You can't rely on your HTML because it is dynamically replaced by BootstrapTable.

    So you need to use its API to retrieve the values. The simplest way is to add script to the page which will get values from table and assign on some (hidden) element in the form.

    Then - on Python side you will read this field and process the data.

    See example (uses JQuery but can be converted to plain JS):

    <script>
        $(document).ready(function () {
            $('#product-form').on('submit', function () {
                const table = $('#products').bootstrapTable('getSelections')
                $('#checkboxes').val(JSON.stringify(table))
            })
        })
    </script>
    

    Some corrections to the template:

    1. Add ID to form
    2. Include product ID as hidden column
    3. Add hidden element which will pass content via form

    html template:

    <form method="post" id="product-form">
        {% csrf_token %}
        <table id="products" class="table-striped" data-toggle="table">
            <thead>
            <tr>
                <th data-field="product_check" data-checkbox="true"></th>
                <th data-field="product_id" data-visible="false">ID</th>
                <th data-field="product">Product</th>
            </tr>
            </thead>
            <input id="checkboxes" name="product_checkboxes" style="display: none">
            {% for product in product_list %}
                <tr>
                    <td><input type="checkbox" data-id="{{ product.id }}" value="{{ product.id }}"></td>
                    <td>{{ product.id }}</td>
                    <td>{{ product.short_name }}</td>
                </tr>
            {% endfor %}
        </table>
        <button id="select-products" onclick="location.href='{% url 'process-products' %}'">Select Products</button>
    </form>
    

    And finally - getting the data in views.py:

    def post(self, request):
        products = json.loads(request.POST.get('product_checkboxes'))
        # process the chosen products
        return redirect('product-list')
    

    Note that in this case products will be a list of objects. Each object has values that are correspondent to columns