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.