Skip to content

Commit 58ca117

Browse files
committedOct 2, 2019
fixed backward compatibility;use columns.data field; release 1.19.0
1 parent e3729e1 commit 58ca117

File tree

4 files changed

+73
-27
lines changed

4 files changed

+73
-27
lines changed
 

‎CHANGES

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
2019.10.02 - 1.19.0
2+
- Fixed backward compatibility with version 1.16
3+
- Use columns.data field (if defined in JavaScript) to determine columns definition
4+
15
2019.06.09 - 1.18.0
26
- Added support for dict (.values) to rendering method (thanks Andreas Hasenkopf)
37

‎README.md

+6-8
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ _django_datatables_view_ uses **GenericViews**, so your view should just inherit
2323
(there is also a DatatableMixin - pure datatables handler that can be used with the mixins of your choice, eg. django-braces). These are:
2424

2525
* **model** - the model that should be used to populate the datatable
26-
* **columns** - the columns that are going to be displayed. If not defined then django_datatables_view will look for 'name' in the columns definition provided in the request by DataTables, eg.: columnDefs: [{name: 'name', targets: [0]} (only works for datatables 1.10+)
27-
* **order_columns** - list of column names used for sorting (eg. if user sorts by second column then second column name from this list will be used with order by clause). If not defined then django_datatables_view will look for 'name' in the columns definition provided in the request by DataTables, eg.: columnDefs: [{name: 'name', targets: [0]} (only works for datatables 1.10+)
26+
* **columns** - the columns that are going to be displayed. If not defined then django_datatables_view will look for 'data' or 'name' in the columns definition provided in the request by DataTables, eg.: columns: [{data: 'first_name'}] (only works for datatables 1.10+)
27+
* **order_columns** - list of column names used for sorting (eg. if user sorts by second column then second column name from this list will be used with order by clause). If not defined then django_datatables_view will look for 'data' or 'name' in the columns definition provided in the request by DataTables, eg.: columns: [{data: 'first_name'}] (only works for datatables 1.10+)
2828
* **filter_queryset** - if you want to filter your DataTable in some specific way then override this method. In case of older DataTables (pre 1.10) you need to override this method or there will be no filtering.
2929
* **filter_method** - returns 'istartswith' by default, you can override it to use different filtering method, e.g. icontains: return self.FILTER_ICONTAINS
3030

@@ -173,18 +173,16 @@ This sample assumes that list of columns and order columns is defined on the cli
173173
$(document).ready(function() {
174174
var dt_table = $('.datatable').dataTable({
175175
order: [[ 0, "desc" ]],
176-
columnDefs: [
176+
columns: [
177177
{
178-
name: 'name',
178+
data: 'name',
179179
orderable: true,
180-
searchable: true,
181-
targets: [0]
180+
searchable: true
182181
},
183182
{
184-
name: 'description',
183+
data: 'description',
185184
orderable: true,
186185
searchable: true,
187-
targets: [1]
188186
}
189187
],
190188
searching: true,

‎django_datatables_view/base_datatable_view.py

+62-18
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class DatatableMixin(object):
2121
none_string = ''
2222
escape_values = True # if set to true then values returned by render_column will be escaped
2323
columns_data = []
24+
is_data_list = True # determines the type of results. If JavaScript passes data attribute that is not an integer
25+
# then it expects dictionary with specific fields in
26+
# the response, see: https://datatables.net/reference/option/columns.data
2427

2528
FILTER_ISTARTSWITH = 'istartswith'
2629
FILTER_ICONTAINS = 'icontains'
@@ -48,16 +51,16 @@ def get_order_columns(self):
4851
By default returns self.order_columns but if these are not defined it tries to get columns
4952
from the request using the columns[i][name] attribute. This requires proper client side definition of
5053
columns, eg:
51-
columnDefs: [
54+
columns: [
5255
{
5356
name: 'username',
57+
data: 'username',
5458
orderable: true,
55-
targets: [0]
5659
},
5760
{
5861
name: 'email',
59-
orderable: false,
60-
targets: [1]
62+
data: 'email',
63+
orderable: false
6164
}
6265
]
6366
"""
@@ -67,9 +70,14 @@ def get_order_columns(self):
6770
# try to build list of order_columns using request data
6871
order_columns = []
6972
for column_def in self.columns_data:
70-
if column_def['name']:
73+
if column_def['name'] or not self.is_data_list:
74+
# if self.is_data_list is False then we have a column name in the 'data' attribute, otherwise
75+
# 'data' attribute is an integer with column index
7176
if column_def['orderable']:
72-
order_columns.append(column_def['name'])
77+
if self.is_data_list:
78+
order_columns.append(column_def['name'])
79+
else:
80+
order_columns.append(column_def.get('data'))
7381
else:
7482
order_columns.append('')
7583
else:
@@ -83,17 +91,16 @@ def get_order_columns(self):
8391
def get_columns(self):
8492
""" Returns the list of columns to be returned in the result set.
8593
By default returns self.columns but if these are not defined it tries to get columns
86-
from the request using the columns[i][name] attribute. This requires proper client side definition of
94+
from the request using the columns[i][data] or columns[i][name] attribute.
95+
This requires proper client side definition of
8796
columns, eg:
8897
89-
columnDefs: [
98+
columns: [
9099
{
91-
name: 'username',
92-
targets: [0]
100+
data: 'username'
93101
},
94102
{
95-
name: 'email',
96-
targets: [1]
103+
data: 'email'
97104
}
98105
]
99106
"""
@@ -102,10 +109,17 @@ def get_columns(self):
102109

103110
columns = []
104111
for column_def in self.columns_data:
105-
if column_def['name']:
106-
columns.append(column_def['name'])
112+
if self.is_data_list:
113+
# if self.is_data_list is true then 'data' atribute is an integer - column index, so we
114+
# cannot use it as a column name, let's try 'name' attribute instead
115+
col_name = column_def['name']
116+
else:
117+
col_name = column_def['data']
118+
119+
if col_name:
120+
columns.append(col_name)
107121
else:
108-
raise Exception('self.columns is not defined and there is no \'name\' defined in columns definition!')
122+
return self.columns
109123

110124
return columns
111125

@@ -252,21 +266,37 @@ def filter_queryset(self, qs):
252266
q = Q()
253267
filter_method = self.get_filter_method()
254268
for col_no, col in enumerate(self.columns_data):
269+
# col['data'] - https://datatables.net/reference/option/columns.data
270+
data_field = col['data']
271+
try:
272+
data_field = int(data_field)
273+
except ValueError:
274+
pass
275+
if isinstance(data_field, int):
276+
column = columns[data_field] # by index so we need columns definition in self._columns
277+
else:
278+
column = data_field
279+
column = column.replace('.', '__')
255280
# apply global search to all searchable columns
256281
if search and col['searchable']:
257-
q |= Q(**{'{0}__{1}'.format(columns[col_no].replace('.', '__'), filter_method): search})
282+
q |= Q(**{'{0}__{1}'.format(column, filter_method): search})
258283

259284
# column specific filter
260285
if col['search.value']:
261286
qs = qs.filter(**{
262-
'{0}__{1}'.format(columns[col_no].replace('.', '__'), filter_method): col['search.value']})
287+
'{0}__{1}'.format(column, filter_method): col['search.value']})
263288
qs = qs.filter(q)
264289
return qs
265290

266291
def prepare_results(self, qs):
267292
data = []
268293
for item in qs:
269-
data.append([self.render_column(item, column) for column in self._columns])
294+
if self.is_data_list:
295+
data.append([self.render_column(item, column) for column in self._columns])
296+
else:
297+
row = {col_data['data']: self.render_column(item, col_data['data']) for col_data in self.columns_data}
298+
data.append(row)
299+
270300
return data
271301

272302
def handle_exception(self, e):
@@ -280,6 +310,20 @@ def get_context_data(self, *args, **kwargs):
280310
# prepare columns data (for DataTables 1.10+)
281311
self.columns_data = self.extract_datatables_column_data()
282312

313+
# determine the response type based on the 'data' field passed from JavaScript
314+
# https://datatables.net/reference/option/columns.data
315+
# col['data'] can be an integer (return list) or string (return dictionary)
316+
# we only check for the first column definition here as there is no way to return list and dictionary
317+
# at once
318+
self.is_data_list = True
319+
if self.columns_data:
320+
self.is_data_list = False
321+
try:
322+
int(self.columns_data[0]['data'])
323+
self.is_data_list = True
324+
except ValueError:
325+
pass
326+
283327
# prepare list of columns to be returned
284328
self._columns = self.get_columns()
285329

‎setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from setuptools import setup, find_packages
22
import os
33

4-
version = '1.18.0'
4+
version = '1.19.0'
55

66
base_dir = os.path.dirname(__file__)
77

0 commit comments

Comments
 (0)
Please sign in to comment.