pythonjquerydjangodjango-views

Sending an array from jQuery to a Django view


I am making a very small application to learn Django. I am send a nested array from jQuery and trying to loop it in my Django view.

The jQuery code is as follows:

$(document).on('click','#exModel',function () {
        const sending = [];
       $("table tr").each(function () {

               var p1 =  $(this).find("th label").html();
               var p2 = $(this).find("td input").attr('id');
               var p3 = $(this).find("td input").val();

               const build = [];
               build.push(p1, p2, p3);
               sending.push(build);
               console.log(sending);
           });
       $.ajax({
               url: '../coreqc/exModel/',
               data: {'sending': sending},
               type: 'post',
               headers: {'X-CSRFToken': '{{ csrf_token }}'},
               async: 'true',
               success: function (data) {
                   
                console.log("I made it back")
                        //dom: 'Bfrtip',

               }
                    });
                });

The above works and takes the following form in the console: Note that the 3rd value is intentionally empty as I sent the form with no values in the fields to get the console read out.

[Log] [["Product A", "1", ""], ["Product B", "2", ""], ["Product C", "3", ""], ["Product D", "4", ""], ["Product E:", "5", ""], ["Product F", "6", ""], ["Product G", "7", ""], ["Product H", "8", ""], ["Product I", "9", ""], ["Product K", "10", ""], …] (36) (coreqc, line 491) 
[Log] I made it back # This is the success text in the above jQuery code

It is making it to my view and I am able to print() the output to the shell:

exModel view:

def exModel(request):
    sentData = request.POST
    print(sentData)

    template = loader.get_template('coreqc/tester.html')
    context = {
    'sentData':sentData
    }
    return HttpResponse(template.render(context, request))

Now, 'sentData' does print to the shell but it does not look right to me or at least the 'sending[1][]' part does not. When I say it does not look right, I do not understand the empty square bracket. I can not access sending like sending[1][2] - I get a dictionary key error.

<QueryDict: {'sending[0][]': ['Product A:', '1', ''], 'sending[1][]': ['Product B', '2', ''], 'sending[2][]': ['Product C', '3', ''], 'sending[3][]': ['Product D', '4', ''], 'sending[4][]': ['Product E', '5', ''], 'sending[5][]': ['Product F', '6', ''], 'sending[6][]': ['Product G', '7', ''], 'sending[7][]': ['Product I', '8', '']}>

What I would like to be able do is to loop through each of values in the QueryDict in a loop in my view, not just print them. However, I am unsure how I access them or whether what is being sent is accessible.

get.values() - works and I can print to console - looks same as above.

I can loop and print like so:

for x, obj in sentData.items():
        print(x)
    
    for y in obj:
        print(y + ':', obj[y])

However I just get this output, it prints the below:

sending[0][]
sending[1][]
sending[2][]
sending[3][]

What I need is to access to the inner values i.e. "Product A", and I am not quite sure on how I do this.

So in summary:

  1. Am I sending the data from jQuery in the right way? right being a way that Python Django can handle.
  2. How do I loop said data to gain access to each data field.

Many thanks for any help.

Update: Following on from comments I have looked heavily into the content being sent Jquery. I found that despite changing headers etc it was coming across as url encoded. I fixed the headers and tested for content type and it is now coming across as application/json. However, the issue I have now is that the request.body is full of '%' symbols like so:

application/json
[26/Oct/2024 09:10:09] "POST /coreqc/exModel/ HTTP/1.1" 200 4631
b'sending%5B0%5D%5B%5D - this continues. I believe all the data is there but maybe it's unicode issue. 

Solution

  • This turned out, after some pointers in another question, to be an access issue. However advice here on json.loads() and request.body() also formed part of the answer. Another additional was JSON.stringify() and that instead of nesting an array in an array, I nested an object inside an array - not sure how much difference that made but its in the end result.

    The JSON being sent was valid. After adding the json.loads() and the using request.body instead of request.POST, I still needed to access the values and keys which I will share below:

    JQuery:

    $(document).on('click','#exModel',function () {
            const sending = [];
           $("table tr").each(function () {
    
                   var p1 =  $(this).find("th label").html();
                   var p2 = $(this).find("td input").attr('id');
                   var p3 = $(this).find("td input").val();
    
                   const build = {bnaa:p1,id:parseInt(p2),vals:parseInt(p3)};
                   
                   sending.push(build);
                  // build.push(p1, p2, p3);
                   
               });
            console.log(sending);
            //console.log(JSON.parse(JSON.stringify(sending)));
           $.ajax({
                   url: '../coreqc/exModel/',
                   data: JSON.stringify({'sending':sending}),
                   //data: {'sending':sending},
                   //processData: false,
                   type: 'POST',
                   headers: {'content_type':'application/json','X-CSRFToken': '{{ csrf_token }}'},
                  // headers: {'X-CSRFToken': '{{ csrf_token }}'},
                   async: 'true',
                   success: function (data) {
                       
                    console.log("I made it back")
                            //dom: 'Bfrtip',
    
                   }
                        });
    

    Then in my view:

    def exModel(request):
            data = request.body
            data = json.loads(request.body)
            print(type(data))
            for i in range(len(data['sending'])):
                print(data['sending'][i]['bnaa'])
                print(data['sending'][i]['id'])
                print(data['sending'][i]['vals'])
    
            template = loader.get_template('coreqc/tester.html')
            context = {
            #'blabla':blabla
            }
            return HttpResponse(template.render(context, request))
    

    Note I have not dealt with the response yet but the above will give you access to individual values, which will print to your terminal.