django-rest-framework-datatables icon indicating copy to clipboard operation
django-rest-framework-datatables copied to clipboard

FieldError when sorting a column which defines a function as the 'data' attribute

Open matthewhegarty opened this issue 5 years ago • 5 comments

My Javascript defines a function for the columns.data attribute:

  $('#player-table').DataTable({
      "serverSide": true,
      "ajax": {
          "url": "{% url "api:player-list" %}?format=datatables",
      },
      "columns": [
        "data": function ( row, type, val, meta ) {
            return row.my_val;
        }
     ]   
})

This works fine when displaying the table - the values are rendered correctly. However, when sorting the column, this sends a request which triggers a crash with FieldError:

Exception Type: FieldError at /api/player/
Exception Value: Cannot resolve keyword 'function' into field. 

Sure enough, the request sends data=function, and I thought that this was the source of the issue, but this actually gets sent with successful requests as well.

Crashes:

http://localhost:8000/api/player/?format=datatables&draw=6&columns%5B0%5D%5Bdata%5D=uid&columns%5B0%5D%5Bname%5D=&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=true&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=function&columns%5B1%5D%5Bname%5D=&columns%5B1%5D%5Bsearchable%5D=false&columns%5B1%5D%5Borderable%5D=true&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B2%5D%5Bdata%5D=netreturn_total_90_day&columns%5B2%5D%5Bname%5D=&columns%5B2%5D%5Bsearchable%5D=false&columns%5B2%5D%5Borderable%5D=true&columns%5B2%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B2%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B3%5D%5Bdata%5D=deposit_total_90_day&columns%5B3%5D%5Bname%5D=&columns%5B3%5D%5Bsearchable%5D=false&columns%5B3%5D%5Borderable%5D=true&columns%5B3%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B3%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B4%5D%5Bdata%5D=withdrawal_total_90_day&columns%5B4%5D%5Bname%5D=&columns%5B4%5D%5Bsearchable%5D=false&columns%5B4%5D%5Borderable%5D=true&columns%5B4%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B4%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B5%5D%5Bdata%5D=id&columns%5B5%5D%5Bname%5D=&columns%5B5%5D%5Bsearchable%5D=false&columns%5B5%5D%5Borderable%5D=true&columns%5B5%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B5%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=1&order%5B0%5D%5Bdir%5D=desc&start=0&length=10&search%5Bvalue%5D=&search%5Bregex%5D=false&range=28&_=1591817768441

Returns OK:

http://localhost:8000/api/player/?format=datatables&draw=1&columns%5B0%5D%5Bdata%5D=uid&columns%5B0%5D%5Bname%5D=&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=true&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=function&columns%5B1%5D%5Bname%5D=&columns%5B1%5D%5Bsearchable%5D=false&columns%5B1%5D%5Borderable%5D=true&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B2%5D%5Bdata%5D=netreturn_total_90_day&columns%5B2%5D%5Bname%5D=&columns%5B2%5D%5Bsearchable%5D=false&columns%5B2%5D%5Borderable%5D=true&columns%5B2%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B2%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B3%5D%5Bdata%5D=deposit_total_90_day&columns%5B3%5D%5Bname%5D=&columns%5B3%5D%5Bsearchable%5D=false&columns%5B3%5D%5Borderable%5D=true&columns%5B3%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B3%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B4%5D%5Bdata%5D=withdrawal_total_90_day&columns%5B4%5D%5Bname%5D=&columns%5B4%5D%5Bsearchable%5D=false&columns%5B4%5D%5Borderable%5D=true&columns%5B4%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B4%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B5%5D%5Bdata%5D=id&columns%5B5%5D%5Bname%5D=&columns%5B5%5D%5Bsearchable%5D=false&columns%5B5%5D%5Borderable%5D=true&columns%5B5%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B5%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=0&order%5B0%5D%5Bdir%5D=asc&start=0&length=10&search%5Bvalue%5D=&search%5Bregex%5D=false&range=28&_=1591817934274

Stack trace:

drfdt_st1.txt

Workaround

Very very nasty hack is to declare an attribute on the model in question called function. This prevents the crash, but sorting still does not work.

matthewhegarty avatar Jun 10 '20 20:06 matthewhegarty

I've reproduced the issue here.

To reproduce:

  • clone the branch
  • Start the example app
  • Click on the 'Album name' 'sort' icon (Full example)

matthewhegarty avatar Jun 11 '20 08:06 matthewhegarty

I am getting the error when search is done. custom functions are not working.

sandeepbalagopal09 avatar Aug 28 '20 06:08 sandeepbalagopal09

hey @matthewhegarty take a look at #83 . set orderable: false, searchable: false,

https://datatables.net/reference/option/columns.orderable

sandeepbalagopal09 avatar Aug 28 '20 07:08 sandeepbalagopal09

This should be documented, as well as other cases where setting orderable: false, searchable: false is necessary to prevent a server side error. PR anyone ? @matthewhegarty @sandeepbalagopal09

izimobil avatar Apr 21 '21 17:04 izimobil

@izimobil why don't you want to use name as alternative to data in this case?

  $('#player-table').DataTable({
      "serverSide": true,
      "ajax": {
          "url": "{% url "api:player-list" %}?format=datatables",
      },
      "columns": [
        "data": function ( row, type, val, meta ) {
            return row.my_val;
        },
        "name": "my_val"
     ]   
})

Just modify that lines https://github.com/izimobil/django-rest-framework-datatables/blob/fab94a9e3d26bd6e393e341cb84d99a406b27db1/rest_framework_datatables/filters.py#L54-L65 like this

col = 'columns[%d][%s]'
data = get_param(request, col % (i, 'data'))
name = get_param(request, col % (i, 'name'))
if (data == 'function') and name:
    data = name

(not a full replacement, just for illustration).

lampslave avatar Apr 02 '23 12:04 lampslave