4

I'm using JqGrid with Django framework. That's JS:

      jQuery("#list").jqGrid({
        url:'{% url views.manage.devicesajax %}',
        datatype: 'json',
        mtype: 'GET',
        colNames:['DID', 'UDID', 'Owner', 'Name', 'First seen', 'Last seen'],
        colModel :[ 
          {name:'did', index:'did', width: 30, searchoptions:{sopt:['eq','ne','bw','cn']}}, 
          {name:'udid', index:'udid', width: 120, editable: true, searchoptions:{sopt:['eq','ne','bw','cn']}}, 
          {name:'d_owner', index:'d_owner', width: 70, editable: true, searchoptions:{sopt:['eq','ne','bw','cn']}}, 
          {name:'d_name', index:'d_name', editable: true, searchoptions:{sopt:['eq','ne','bw','cn']}}, 
          {name:'d_firstseen', index:'d_firstseen', width: 80}, 
          {name:'d_lastseen', index:'d_lastseen', width: 80}],
        pager: jQuery('#pager'),
        rowNum:20,
        rowList:[20,50,100],
        sortname: 'did',
        sortorder: "desc",
        multiselect: true,
        viewrecords: true,
        imgpath: 'themes/basic/images',
        caption: 'Devices list',
        height: 330,
        width: 1000,
        onSelectRow: function(id) {
            var id = $("#list").getRowData(id).message_id;
            message_id = id;
        },
        editurl: "{% url views.manage.deviceseditajax %}"
    });

When I do edit row in JqGrid I get error from editurl:

Forbidden (403) CSRF verification failed. Request aborted.

It's because csrf_token doesn't pass to editurl with the other data. How to add csrf_token to the POST request to editurl ?

This code works perfectly ( complete piece of jqgrid init ):

     jQuery("#list").jqGrid({
        url:'{% url views.manage.devicesajax %}',
        datatype: 'json',
        mtype: 'GET',
        colNames:['DID', 'UDID', 'Owner', 'Name', 'First seen', 'Last seen'],
        colModel :[ 
          {name:'did', index:'did', width: 30, searchoptions:{sopt:['eq','ne','bw','cn']}}, 
          {name:'udid', index:'udid', width: 120, editable: true, searchoptions:{sopt:['eq','ne','bw','cn']}}, 
          {name:'d_owner', index:'d_owner', width: 70, editable: true, searchoptions:{sopt:['eq','ne','bw','cn']}}, 
          {name:'d_name', index:'d_name', editable: true, searchoptions:{sopt:['eq','ne','bw','cn']}}, 
          {name:'d_firstseen', index:'d_firstseen', width: 80}, 
          {name:'d_lastseen', index:'d_lastseen', width: 80}],
        pager: jQuery('#pager'),
        rowNum:20,
        rowList:[20,50,100],
        sortname: 'did',
        sortorder: "desc",
        multiselect: true,
        viewrecords: true,
        imgpath: 'themes/basic/images',
        caption: 'Devices list',
        height: 330,
        width: 1000,
        editurl: "{% url views.manage.deviceseditajax %}",
    });

      jQuery("#list").navGrid('#pager',{edit:true,add:true,del:true,search:true},
        {
            closeAfterEdit:true,
            reloadAfterSubmit:true,
            closeOnEscape:true,
            editData: {csrfmiddlewaretoken: '{{ csrf_token }}'}
        },
        {
            closeAfterAdd:true,
            reloadAfterSubmit:true,
            closeOnEscape:true,
            editData: {csrfmiddlewaretoken: '{{ csrf_token }}'}
        }, 
        {
            closeOnEscape:true,
            delData: {csrfmiddlewaretoken: '{{ csrf_token }}'}
        }, 
        {
         caption: "Search",
         Find: "Find",
         Reset: "Reset",
         sopt  : ['eq', 'cn'],
         matchText: " match",
         rulesText: " rules",
         closeAfterSearch: true,
         afterShowSearch: function ()
         {
             $('#reset_filter1_block').show();
         }
       }
      );
Denis
  • 759
  • 1
  • 9
  • 22

4 Answers4

3

I don't use Django framework and not familiar with the csrf_token, but after searching in Google it seems that you need to set it in the HTTP header of the request: xhr.setRequestHeader('X-CSRF-Token', csrf_token);. To do this in case of jqGrid you can use loadBeforeSend event handler:

loadBeforeSend: function(jqXHR) {
    // you should modify the next line to get the CSRF tocken
    // in any way (for example $('meta[name=csrf]').attr('content')
    // if you have <meta name="csrf" content="abcdefjklmnopqrstuvwxyz="/>)
    var csrf_token = '<%= token_value %>'; // any way to get
    jqXHR.setRequestHeader('X-CSRF-Token', csrf_token);
}

See here for a very close problem.

UPDATED: To post additional data in case of form editing usage you can use editData: editData: { csrfmiddlewaretoken:'<%= token_value %>' }. For example:

jQuery("#list").jqGrid('navGrid','#pager',{},
    { // Edit option (parameters of editGridRow method)
        recreateForm:true,
        reloadAfterSubmit:false,
        closeOnEscape:true,
        savekey: [true,13],
        closeAfterEdit:true,
        ajaxEditOptions: {
            beforeSend: function(jqXHR) {
                // you should modify the next line to get the CSRF tocken
                // in any way (for example $('meta[name=csrf]').attr('content')
                // if you have <meta name="csrf" content="abcdefjklmnopqrstuvwxyz="/>)
                var csrf_token = '<%= token_value %>'; // any way to get
                jqXHR.setRequestHeader('X-CSRF-Token', csrf_token);
            }
        },
        editData: {
            csrfmiddlewaretoken: '<%= token_value %>'
        }
    },
    { // Add options (parameters of editGridRow method)
        recreateForm:true,
        reloadAfterSubmit:false,
        closeOnEscape:true,
        savekey: [true,13],
        closeAfterAdd:true,
        ajaxEditOptions: {
            beforeSend: function(jqXHR) {
                // you should modify the next line to get the CSRF tocken
                // in any way (for example $('meta[name=csrf]').attr('content')
                // if you have <meta name="csrf" content="abcdefjklmnopqrstuvwxyz="/>)
                var csrf_token = '<%= token_value %>'; // any way to get
                jqXHR.setRequestHeader('X-CSRF-Token', csrf_token);
            }
        },
        editData: {
            csrfmiddlewaretoken: '<%= token_value %>'
        }
    }
);

I placed here both ways: setting of 'X-CSRF-Token' HTTP header and posting of the csrfmiddlewaretoken parameter. You can remove one way after the corresponding experiments.

If you use some parameters for all grids on the page you can better change the defaults (see here for details)

jQuery.extend(jQuery.jgrid.edit, {
    recreateForm:true,
    reloadAfterSubmit:false,
    closeOnEscape:true,
    savekey: [true,13],
    closeAfterAdd:true,
    closeAfterEdit:true,
    ajaxEditOptions: {
        beforeSend: function(jqXHR) {
            // you should modify the next line to get the CSRF tocken
            // in any way (for example $('meta[name=csrf]').attr('content')
            // if you have <meta name="csrf" content="abcdefjklmnopqrstuvwxyz="/>)
            var csrf_token = '<%= token_value %>'; // any way to get
            jqXHR.setRequestHeader('X-CSRF-Token', csrf_token);
        }
    },
    editData: {
        csrfmiddlewaretoken: '<%= token_value %>'
    }
});

The setting is common for both Add and Edit forms. So you can use navGrid in the simplified form.

jQuery("#list").jqGrid('navGrid','#pager');
Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • @futureboxlab : Just now I reread your question and find out that you have problem not in filling of the grid content, but in the grid editing. So you should use `beforeSend` handler of the `jQuery.ajax` which do the same which I described in my answer. To set the event handler in case of inline editing you can use `ajaxRowOptions` option or `ajaxEditOptions` option in case of the usage of the forme editing. – Oleg Jun 25 '11 at 11:14
  • I've tried it. But it sends such header when fetching records, not when it's doing POST request to the editurl. – Denis Jun 25 '11 at 11:15
  • @futureboxlab: I agree. I just wrote you the corresponding comment. If you need I could explain the same more detailed. – Oleg Jun 25 '11 at 11:17
  • @futureboxlab: First of all we should clear the following question: which editing mode you use: [inline editing](http://www.trirand.com/jqgridwiki/doku.php?id=wiki:inline_editing) or [form editing](http://www.trirand.com/jqgridwiki/doku.php?id=wiki:form_editing)? The next question: do you want to set the `X-CSRF-Token` HTTP header in all your edit requests of only in the selected one? – Oleg Jun 25 '11 at 11:31
  • I use form edititng. I need it for all requests. One more thing: I'm not sure headerparam will work, but post variable will work for sure – Denis Jun 25 '11 at 12:20
  • @futureboxlab: I wrote you before that I not familiar with Django framework. Which parameter should be send`? Is it `csrfmiddlewaretoken` parameter like mhoareau suggested? Is '<%= token_value %>' the correct value or you need get it from the cookie? – Oleg Jun 25 '11 at 12:34
  • I can render it into template easily like: {{ csrf_token }} Only thing I don't know is how to send it with the editing post request. – Denis Jun 25 '11 at 12:52
  • @futureboxlab: I updated my answer. I hope now you will find the solution of your problem. – Oleg Jun 25 '11 at 13:31
  • Thank you. Your solution has helped. It's important to put editData param at the correct section: `jQuery("#list").navGrid('#pager', {edit:true,add:true,del:true,search:true}, { closeAfterEdit:true, reloadAfterSubmit:true, closeOnEscape:true, editData: {csrfmiddlewaretoken: '{{ csrf_token }}'} }, ... } );` – Denis Jun 27 '11 at 01:25
0

I found simple solution using latest JqGrid and Inline Edit submit csrf_token to request POST django without @csrf_exempt

onSelectRow: function(id){
     if(id && id!==lastSel){ 
        $(selector).restoreRow(lastSel); 
        lastSel=id; 
     }

     var editparameters = {
        extraparam: {csrfmiddlewaretoken: $('.token-data').data('token')},
        keys: true,
      };
     $(selector).jqGrid('editRow', id, editparameters);

}

For example, please see on my blog post: http://yodi.polatic.me/jqgrid-inline-editing-integration-with-django-send-csrf-token/

yodi
  • 942
  • 8
  • 10
0

Check your cookies. Django's CSRF also save a cookie csrftoken which does have the same value as the csrf_token which you would use in a form. You can use any Javascript cookie library to get the cookie and pass it to the POST request as csrfmiddlewaretoken.

Torsten Engelbrecht
  • 13,318
  • 4
  • 46
  • 48
  • I know that. It's easy to get csrftoken value. But I have no idea how to add it to the post params. Is any jqjrid method for this ? – Denis Jun 25 '11 at 07:21
0

According to the jqGrid documentation, you can pass a postData options. If you're using jQuery Cookie plugin, you can add something like :

postData: {
    csrfmiddlewaretoken: $.cookie(CSRF_COOKIE_NAME)
},

to your list of options to jqGrid.

The CSRF_COOKIE_NAME is set in your django application settings.py and is 'csrftoken' by default.

mhoareau
  • 631
  • 5
  • 6