Home > Software engineering >  Django BaseDataTableView - filter_queryset method not work
Django BaseDataTableView - filter_queryset method not work

Time:11-05

I am using BaseDatatableView and DataTable jquery. I've already written several views for BaseDatatableView and there were no problems until I had to override the 'prepare_results' and 'render_column' methods. I need to present the results of instance methods in a table, so I overwrite the methods of the BaseDatatableView class.

This is my code in views.py

class MyModelDatatable(BaseDatatableView):
    model = MyModel
    columns = ['field1', 'field2', 'id']
    columns_searched = [col for col in columns if col != 'id']
    
    def get_initial_queryset(self):
        return self.model.objects.all()

    def filter_queryset(self, qs):
        print('test')  # not displayed
        search_text = self.request.GET.get('search[value]', None)
        if search_text:
            search_terms = search_text.split()
            query = Q()

            for col in self.columns_searched:
                or_conditions = Q()

                for term in search_terms:
                    or_conditions |= Q(**{f'{col}__icontains': term})

                query |= or_conditions    

            qs = qs.filter(query)

        return qs

    def prepare_results(self, qs):
        data = []
        for item in qs:
            item_str = str(item)
            data.append({

                'field1': item_str,
                'field2': item.field2,
                'id': item.id
            })

        return data

    def render_column(self, row, column):
        if column == 'field2':
            return row.field2.strftime('%Y-%m-%d')
        return super(OrderDatatable, self).render_column(row, column)

    def get(self, request, *args, **kwargs):
        return self.get_json_response()

    def get_json_response(self):
        draw = int(self.request.GET.get('draw', 1))
        total_records = self.get_initial_queryset().count()
        total_display_records = total_records
        start = int(self.request.GET.get('start', 0))
        length = int(self.request.GET.get('length', 10))
        end = start   length
        data = self.prepare_results(self.get_initial_queryset()[start:end])
        response = {
            'draw': draw,
            'recordsTotal': total_records,
            'recordsFiltered': total_display_records,
            'data': data,
        }

        return JsonResponse(response)

objDatatable.js

$(document).ready(function () {
    const table = $('#my-datatable').DataTable({
        'columns': [

            {'data': 'field1'},
            {'data': 'field2'},
            {
                'data': 'id',
                'render': function (data, type, row) {
                    let actionButtons = `
                        <a  href='/edit/${data}'
                            >
                            <i data-feather="edit"></i>
                        </a>
                    `;
                    return actionButtons;
                }
            },
    
        ],
        'paging': true,
        'pageLength': 20,
        'lengthMenu': [5, 10, 20, 30, 50, 100, 200],
        'pagingType': 'full_numbers',
        'processing': true,
        'serverSide': true,
        'ajax': {
            'url': 'orders_datatable_search/',
       
        }
    });
    table.on('draw.dt', function () {
        feather.replace();
    })
});

With standard class fields without method overrides, filtering works correctly. After overwriting, everything works as it should, including pagination, but not filtering.

CodePudding user response:

Well your get_json_response produces items, but they completely omit the filtering, ordering and pagination logic, as you can see in the original implementation [GitHub].

You will thus have to reimplement that yourself:

class MyModelDatatable(BaseDatatableView):
    model = MyModel
    columns = ['field1', 'field2', 'id']
    columns_searched = [col for col in columns if col != 'id']

    def get_initial_queryset(self):
        return self.model.objects.all()

    def filter_queryset(self, qs):
        print('test')
        search_text = self.request.GET.get('search[value]', None)
        if search_text:
            search_terms = search_text.split()
            query = Q()
            for col in self.columns_searched:
                or_conditions = Q()
                for term in search_terms:
                    or_conditions |= Q(**{f'{col}__icontains': term})
                query |= or_conditions
            qs = qs.filter(query)
        return qs

    def prepare_results(self, qs):
        data = []
        for item in qs:
            item_str = str(item)
            data.append(
                {'field1': item_str, 'field2': item.field2, 'id': item.id}
            )
        return data

    def render_column(self, row, column):
        if column == 'field2':
            return row.date.strftime('%Y-%m-%d')
        return super(OrderDatatable, self).render_column(row, column)

    def paging(self, qs):
        start = int(self.request.GET.get('start', 0))
        length = int(self.request.GET.get('length', 10))
        return qs[start : start   length]

    def get(self, request, *args, **kwargs):
        return self.get_json_response()

    def get_json_response(self):
        draw = int(self.request.GET.get('draw', 1))
        qs = self.get_initial_queryset()
        total_records = qs.count()
        qs = self.filter_queryset(qs)
        total_display_records = qs.count()
        qs = self.ordering(qs)
        qs = self.paging(qs)
        response = {
            'draw': draw,
            'recordsTotal': total_records,
            'recordsFiltered': total_display_records,
            'data': data,
        }
        return JsonResponse(response)

I'm however not really following why you are here implementing the entire logic again. This is almost equivalent to the original. So just by overriding the paging method, and some others, you let the BaseDatatableView view handle the logic. It will return a JsonResponse anway, so you are reimplementing boilerplate code.

  • Related