Django/django-tables2 html table on row click to edit form

Kieron Gilbey picture Kieron Gilbey · Sep 16, 2018 · Viewed 7.7k times · Source

sorry this post may be messy not sure how do explain what I am looking for very well but here goes nothing.

I have a Django App and using django-table2 to print a data model to a table, the next thing I am looking to do it when the user clicks on the table row to redirect the page to a equivalent edit form

urls.py

path('', CustomerView.as_view(), name='customer'),
path('customer_edit/', views.customer_edit, name='customer_edit'),

tables.py

import django_tables2 as tables
from customer.models import Customer


class CustomerTable(tables.Table):
    account = tables.Column(attrs={'td': {'class': 'account'}})

    class Meta:
        model = Customer
        attrs = {'id': 'table'}
        exclude = ('is_deleted',)
        template_name = 'django_tables2/bootstrap-responsive.html'

views.py

from django.shortcuts import render
from django_tables2 import RequestConfig
from customer.models import Customer
from customer.tables import CustomerTable
from django.views.generic import TemplateView


class CustomerView(TemplateView):
    template_name = 'customer/customer.html'

    def get(self, request, *args, **kwargs):
        table = CustomerTable(Customer.objects.all().filter(is_deleted=False))
        RequestConfig(request).configure(table)
        return render(request, 'customer/customer.html', {'table': table})

    def customer_edit(request):
        return render(request, 'customer/customer_edit.html')

template

{% extends 'base.html' %}
{% load render_table from django_tables2 %}

{% block head %}
    <title>Dev Genie - Customers</title>
{% endblock %}

{% block body %}
    <div class="input-group col-md-6">
        <input type="button" class="btn btn-success" value="Add">
        <input type="button" class="btn btn-danger" value="Delete">
        <input class="form-control py-2" type="search" value="search" id="example-search-input">
        <span class="input-group-append">
        <button class="btn btn-outline-secondary" type="button">
            <span class="glyphicon glyphicon-search"></span>
        </button>
      </span>
    </div>
    {% render_table table %}
    <script>
        $(document).ready(function () {
            $('table:first').children('tbody:first').children('tr:first').css('background-color', '#0099ff');
            $('table tbody tr').bind("mouseover", function () {
                var colour = $(this).css("background-color");
                $(this).css("background", '#0099ff');

                $(this).bind("mouseout", function () {
                    $(this).css("background", colour);
                });
            });
            $('table tbody tr').click(function () {
                let account = $(this).closest('tr').find('td.account').text();
                alert(account);
                //on table row click event, pass back to django
            });
        });
    </script>
{% endblock %}

I am struggling to get the account code from the onclick even to pass the account code back to Django to move to the next page to begin editing the record

I really think I am barking up the wrong tree with this

any help would be very much appreciated

Answer

Viktor Johansson picture Viktor Johansson · Oct 14, 2019

I couldn't find any solution that suits my needs.

All the solutions I found requires some weird processing in Javascript and parsing slugs and PK's from the table to redirect to the correct URL.

My solution?

Define an absolute URL in your models.py

def get_absolute_url(self):
    return reverse('product:detail', kwargs={'slug': self.slug})

Then in your tables.py, we add a data-href attribute to each column that we want to be clickable. This allows us to restrict which columns become clickable.

class ProductTable(tables.Table):
    clickable = {'td': {'data-href': lambda record: record.get_absolute_url}}
    name = tables.Column(attrs=clickable)
    in_stock = tables.Column(attrs=clickable)

    class Meta:
        model = Product
        fields = (name, in_stock)

And in your template just add this simple event listener,

$(document).ready(function($) {
    $("td").click(function() {
        window.location = $(this).data("href");
    });
});

Alternatively, if you just want the whole row to be clickable, just use Row attributes as defined in the docs,

class ProductTable(tables.Table):
    class Meta:
        model = Product
        row_attrs = {'data-href': lambda record: record.get_absolute_url}
        fields = (name, in_stock)

and then change your template script too

$(document).ready(function($) {
    $("tr").click(function() {
        window.location = $(this).data("href");
    });
});