Datatables Editor Create returns "POST http://127.0.0.1:8000/dashboard 400 (Bad Request)"

Datatables Editor Create returns "POST http://127.0.0.1:8000/dashboard 400 (Bad Request)"

Hamjam31Hamjam31 Posts: 15Questions: 3Answers: 0

Hello, I am trying to integrate DataTables Editor with Django and a Django REST framework API. I have created the API and am able to post data. However, when I connect it with a datatables and try to click create, I am returned an error 400 Bad Request. Would love to get some feedback if I am missing something within the Editor. Additionally if anyone knows resources where others have been able to connect Django with Datatables Editor, please connect me with them.

{% extends 'base_datatables_editor.html' %}

{% block content %}
<h1 style="text-align: center; padding-top: 1em; padding-bottom: 1em;">Investigators</h1>
<div class="row">
    <div class="col-sm-12">
        <table id="InvestigatorDataTable" class="table table-striped table-bordered" style="width:100%">
            <thead>
                <tr>
                    <th scope="col">First Name</th>
                    <th scope="col">Last Name</th>
                    <th scope="col">Name</th>
                    <th scope="col">Email</th>
                    <th scope="col">Institution</th>
                </tr>
            </thead>
        </table>
    </div>
</div>
{% endblock content %}

{% block extra_js %}
    <script>  
        var editor;
        var DateTime = moment().format();

        function getCookie(name) {
            var cookieValue = null;
            if (document.cookie && document.cookie != '') {
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }

        $(document).ready(function() {

            function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
            }
            $.ajaxSetup({
            beforeSend: function (xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
            });

            var csrftoken = getCookie('csrftoken');
            editor = new $.fn.dataTable.Editor( {
                ajax: {
                    create: {
                    type: "POST",
                    url:  'http://127.0.0.1:8000/dashboard/api/investigator/'
                    },
                    ///edit: {
                    ///type: "PUT",
                    ///url:  "http://127.0.0.1:8000/dashboard/api/investigator/_id_"
                    ///},
                    ///remove: {
                    ///type: "DELETE",
                    ///url:  "http://127.0.0.1:8000/dashboard/api/investigator/_id_"
                    },
                data: "symbol",
                defaultContent: "",
                contentType: 'application/json',
                csrfmiddlewaretoken: window.CSRF_TOKEN,
                table: '#InvestigatorDataTable',
                idSrc: "id",
                dataSrc: "data",
                fields: [ {
                    label: "ID:",
                    name: "id"
                }, {
                    label: "Last Name:",
                    name: "last_name"
                }, {
                    label: "First Name:",
                    name: "first_name"
                }, {
                    label: "Email:",
                    name: "email"
                }, {
                    label: "Institution:",
                    name: "institution.id",
                    ///type: "select",
                    ///placeholder: "Select an institution"
                }, {
                    label: "Created At:",
                    name: "created_at",
                }] 
            });
            $('#InvestigatorDataTable').DataTable({
                serverSide: true,
                ajax: {
                    url: "http://127.0.0.1:8000/dashboard/api/investigator/?format=datatables",
                    type: 'GET',
                },
                dom: 'Bfrtrip',
                columns: [
                    {data: "last_name", },
                    {data: "first_name",},
                    {data: null, render: function ( data, type, row ) {
                        return data.first_name + " " + data.last_name
                    }},
                    {data: "email", orderable: false},
                    {data: "institution", name: "institution", orderable: true},
                    ],
                columnDefs: [
                    { targets: [2, 3, 4,], visible: true},
                    { targets: '_all', visible: false }
                ],
                select: true,
                buttons: [
                    { extend: "create", editor: editor },
                    { extend: "edit", editor: editor }, 
                    { extend: "remove", editor: editor }
                ]
            });
        });
    </script>
{% endblock %}

The XHR response for the POST request seems to have all the necessary fields yet it still rejects it.

Answers

  • kthorngrenkthorngren Posts: 21,343Questions: 26Answers: 4,954

    You will need to look at your Django server logs to determine why its responding with the 400 Bad Request error.

    I've not sued this but here is a djangorestframework-datatables-editor framework.

    Kevin

  • Hamjam31Hamjam31 Posts: 15Questions: 3Answers: 0
    edited February 2023

    Thank you however the linked project no longer works. Surprisingly, it runs into the same error where the editor create button shows 400 Bad Request.

    I did have one thought, currently when the data is being sent, the JSON data looks like this. (I removed both the "id" and "created_at" field because API has an html form that accepts data without these fields)

    {
      "0": {
        "last_name": "test",
        "first_name": "test",
        "email": "test@gmail.com",
        "institution": "1"
      }
    }
    

    How can I edit the data to look like this?

      {
        "last_name": "test",
        "first_name": "test",
        "email": "test@gmail.com",
        "institution": 1
      }
    
  • kthorngrenkthorngren Posts: 21,343Questions: 26Answers: 4,954
    edited February 2023

    Maybe this thread with a similar question will help.

    Did you look at the Django server logs to see why its returning a 400 error?

    Maybe with the djangorestframework-datatables-editor library you need to send the data from the client not using JSON. I haven't used that library so not sure how well it works. Looks like its been a couple years since its been updated.

    How can I edit the data to look like this?

    The docs show what the Create data looks like. Which looks to be the same as the JSON structure being sent. I think the preSubmit might be the place to modify the data sent.

    Kevin

  • Hamjam31Hamjam31 Posts: 15Questions: 3Answers: 0

    I looked at the Django Error Log and they only thing it has is

    Bad Request: /dashboard/api/investigator/
    "POST /dashboard/api/investigator/ HTTP/1.1" 400 160
    

    After expanding the logs to include more info.
    Fomat: {levelname} {name} {filename} {funcName} {processName} {module} {lineno:d} {message}
    (For reference on logging definitions - https://docs.python.org/3/library/logging.html#logrecord-attributes)

    WARNING django.request log.py log_response MainProcess log None 225 Bad Request: /dashboard/api/investigator/
    WARNING django.server basehttp.py log_message MainProcess basehttp None 179 "POST /dashboard/api/investigator/ HTTP/1.1" 400 160
    

    I'll look into sending the data not using JSON/changing how the JSON structure and post a comment with what I learn.

  • kthorngrenkthorngren Posts: 21,343Questions: 26Answers: 4,954

    If it were me I would dig deeper into why the 400 is returned. Looking at this page it seems to indicate that the reason might be noted in the response. Use the browser's network inspector tool to see the response.

    Using google it seems not setting the ALLOWED_HOSTS is a common issue with Django responding with 400 error. For example:
    https://blog.anvileight.com/posts/how-to-fix-bad-request-400-in-django/

    This SO thread indicates setting the DEBUG flag to True will allow seeing the error.

    I'll look into sending the data not using JSON

    I meant for this change if you are using the djangorestframework-datatables-editor framework. I don't see anything in their example where they are telling the Editor to send JSON data. It may support either, I'm not sure.

    Kevin

  • Hamjam31Hamjam31 Posts: 15Questions: 3Answers: 0

    Thank you very much for all the help. Looking at the browser's network inspector has given me more information. For some reason none of the data from the fields is being entered prior to submitting.

  • kthorngrenkthorngren Posts: 21,343Questions: 26Answers: 4,954
    edited February 2023

    Take a look at the Payload tab to see how the fields are sent. The errors suggest that your Django route is not parsing the create data that is being sent. Possibly you will want to send the data in JSON format. The last example in the ajax.data shows how to do this.

    Also you will need to get the fields from the 0 key as shown in the Editor Client/Server exchange for create docs. Does the payload tab show the correct data, as per the docs, being sent to the server?

    As I suggested above you might be able to use the preSubmit event to modify the data sent for the create action to go from

    {
      "0": {
        "last_name": "test",
        "first_name": "test",
        "email": "test@gmail.com",
        "institution": "1"
      }
    }
    

    to

    {
      "last_name": "test",
      "first_name": "test",
      "email": "test@gmail.com",
      "institution": 1
    }
    

    I haven't used Django enough to tell you exactly how to do this. The Datatables developer is not familiar with Django. If you don't want to use thedjangorestframework-datatables-editor library maybe you can look at the source code to see how it parses the data. Or maybe there is another framework that will work for you.

    Kevin

  • Hamjam31Hamjam31 Posts: 15Questions: 3Answers: 0

    Looks like the payload tab has the same data structure from the initial JSON format that I'm trying to change.

    I have also added in the preSubmit option into my editor file and it is still not working. Perhaps I created it wrong?

    {% block extra_js %}
        <script>  
            var editor;
            var DateTime = moment().format();
    
            function getCookie(name) {
                var cookieValue = null;
                if (document.cookie && document.cookie != '') {
                    var cookies = document.cookie.split(';');
                    for (var i = 0; i < cookies.length; i++) {
                        var cookie = jQuery.trim(cookies[i]);
                        // Does this cookie string begin with the name we want?
                        if (cookie.substring(0, name.length + 1) == (name + '=')) {
                            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                            break;
                        }
                    }
                }
                return cookieValue;
            }
    
            $(document).ready(function() {
    
                function csrfSafeMethod(method) {
                // these HTTP methods do not require CSRF protection
                return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
                }
                $.ajaxSetup({
                beforeSend: function (xhr, settings) {
                    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                        xhr.setRequestHeader("X-CSRFToken", csrftoken);
                    }
                }
                });
    
                var csrftoken = getCookie('csrftoken');
                editor = new $.fn.dataTable.Editor( {
                    ajax: {
                        url: "http://127.0.0.1:8000/dashboard/api/investigator/",
                        contentType: "application/json", 
                        data: function ( d ) {
                            return JSON.stringify( d );
                    }},
                    ///data: "symbol",
                    ///dataType: 'application/json',
                    ///csrfmiddlewaretoken: window.CSRF_TOKEN,
                    table: '#InvestigatorDataTable',
                    ///idSrc: "id",
                    ///dataSrc: "0",
                    fields: [ {
                        label: "Last Name:",
                        name: "last_name"
                    }, {
                        label: "First Name:",
                        name: "first_name"
                    }, {
                        label: "Email:",
                        name: "email"
                    }, {
                        label: "Institution:",
                        name: "institution",
                        data: function ( d ) {
                            return JSON.parseInt( d )},
                        ///type: "select",
                        ///placeholder: "Select an institution"
                    }] 
                });
                editor.on('preSubmit', function (e, data, create ) {
                    result = data.data[0]
                    result.institution = parseInt(result.institution)
                    ///console.log(result)
                    return result;
                    });
    
                $('#InvestigatorDataTable').DataTable({
                    serverSide: true,
                    ajax: {
                        url: "http://127.0.0.1:8000/dashboard/api/investigator/?format=datatables",
                        type: 'GET',
                    },
                    dom: 'Bfrtrip',
                    columns: [
                        {data: "last_name", },
                        {data: "first_name",},
                        {data: null, render: function ( data, type, row ) {
                            return data.first_name + " " + data.last_name
                        }},
                        {data: "email", orderable: false},
                        {data: "institution", name: "institution", orderable: true},
                        ],
                    columnDefs: [
                        { targets: [2, 3, 4,], visible: true},
                        { targets: '_all', visible: false }
                    ],
                    select: true,
                    buttons: [
                        { extend: "create", editor: editor },
                        { extend: "edit", editor: editor }, 
                        { extend: "remove", editor: editor }
                    ]
                });
            });
        </script>
    {% endblock %}
    
  • kthorngrenkthorngren Posts: 21,343Questions: 26Answers: 4,954
    edited February 2023

    It looks like you are using preSubmit incorrectly. You don't want to return anything. It uses the return value to determine if the form should be submitted, ie, a boolean value.

    Look at the example in the docs and you will see it is simply updating the data parameter. You will probably want something like this (I haven't tested this):

    editor.on( 'preSubmit', function ( e, data, action ) {
      if ( action === 'create' ) {
        data = data.data[0];
      }
    } );
    

    The Edit and Delete processes use the same structure with the key being the row ID. Is your server script setup to parse this data?

    Kevin

  • Hamjam31Hamjam31 Posts: 15Questions: 3Answers: 0

    Thanks for all the help. After thoroughly going through the linked example app, turns out I was using the wrong API url. The proper URL should be http://127.0.0.1:8000/dashboard/api/investigator/editor/?format=datatables rather than http://127.0.0.1:8000/dashboard/api/investigator/. This is why it kept returning ERROR 400 because it was not being properly read.

  • allanallan Posts: 63,523Questions: 1Answers: 10,473 Site admin

    Great to hear you got to the bottom of it. Thanks for letting us know.

    Allan

Sign In or Register to comment.