Search code examples
djangodjango-filterdjango-tables2

custom sorting for table in django-tables2


I have a table with django-tables2 on one site with django-filter as well. I am using PagedFilteredTableView that looks like this:

class PagedFilteredTableView(SingleTableView):
    filter_class = None
    formhelper_class = None
    context_filter_name = 'filter'

    def get_queryset(self, **kwargs):
        qs = super(PagedFilteredTableView, self).get_queryset()
        self.filter = self.filter_class(self.request.GET, queryset=qs)
        self.filter.form.helper = self.formhelper_class()
        return self.filter.qs

    def get_context_data(self, **kwargs):
        context = super(PagedFilteredTableView, self).get_context_data()
        context[self.context_filter_name] = self.filter
        return context

This is view:

def sorted_str_number(str):
    return int(str)


class PageList(PagedFilteredTableView):

    model = Page
    table_class = PageTable
    filter_class = PageListFilter
    formhelper_class = PageListFormHelper

    pagination = {
        '20': 20,
        '50': 50,
        '100': 100,
    }

    def get_table_class(self):
        klass = super().get_table_class()
        if 'pagination' in self.request.GET:
            klass._meta.per_page = int(self.request.GET['pagination'])
        return klass

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['per_page_table'] = sorted(self.pagination.keys(), key=sorted_str_number)
        return context

I need to implement natural sort for one column. I thought I could override order behaviour in tables.py like this:

class PageTable(Table):
    column_name = Column(verbose_name='ID')

    def order_column_name(self, queryset, is_descending):  
        return sorted(queryset, key=lambda q: natural_sort_key(q.column_name)), True

But order_column_name method is ignored. Where should I override custom sorting for one field when using django-tables2 and django-filter?


Solution

  • Quoting the documentation you link to:

    Adding a Table.order_FOO method (where FOO is the name of the column), gives you the ability to chain to, or modify, the original queryset when that column is selected to be ordered.

    What you do is sorting the queryset in python, which might work if you convert the queryset to a list first, but it looks like you are mixing it too much now.

    That said, you say the order_column_name is ignored. Is it called at all? If I try to rebuild your example (stripping of the filtering stuff, I get errors, but the method is being called.