1

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?

Lucas03
  • 2,267
  • 2
  • 32
  • 60

1 Answers1

0

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.

Jieter
  • 4,101
  • 1
  • 19
  • 31
  • I added `column_name` as param in table. It is not called, I added print statement there and I can not see it in output from `runserver` – Lucas03 Jun 07 '16 at 08:14
  • But it does render a table having a column called `column_name`? – Jieter Jun 07 '16 at 08:17
  • yes it does and column is sortable(default sort, not natural). May be django-filter overrides sorting? – Lucas03 Jun 07 '16 at 08:22
  • hm, looks like I was using old version with no `order_FOO` support? – Lucas03 Jun 07 '16 at 08:28
  • now I do get errors `expected string or bytes-like object`. Can I add natural sort to table? – Lucas03 Jun 07 '16 at 08:32
  • 1
    Custom ordering is only supported for querysets right now, see https://github.com/bradleyayers/django-tables2/blob/master/django_tables2/tables.py#L105-L110 – Jieter Jun 07 '16 at 08:40
  • I know this comment is old, but if anyone else is despairing after reading it while trying to figure out why django-tables2 won't call the custom sort when displaying a list of dicts I found a work around. If you create a [render_FOO function](https://django-tables2.readthedocs.io/en/latest/pages/custom-data.html#table-render-foo-methods), you can pass in a list of info that sorts, and then just display the info you care about. For instance, if you want to sort by name ignoring case, have each dictionary contain a list of name.lower() and name, and then just return the name from render_name() – wile_e8 Dec 07 '20 at 21:32